@@ -197,18 +197,35 @@ void func() {
197
197
` extern int globe; `
198
198
告诉编译器变量存在哪里。
199
199
200
+ ###### extern c
201
+
202
+ 有时候会经常在C和C++中进行相互调用。
203
+
204
+ 在实际项目中,如果一个C++工程需要调用C语言编写的静态库或者动态库,那么可以直接调用吗?
205
+
206
+ 显然是不可以直接调用的,对于C++代码,因为C++有自己的函数名修饰规则,在编译和汇编阶段形成符号表的时候,编译器是按照C++自己的函数名修饰规则来表示符号的,而对于C的代码,也有自己的函数名修饰规则,在编译和汇编阶段,编译器是按照C的函数名修饰规则来形成符号表的,那么在链接阶段,由于符号表中表示同一函数的符号名都是不同的,链接器无法找到相应函数的地址,也就无法进行符号表的合并和重定位,就会产生链接错误。
207
+
208
+ 同理,一个C工程要调用C++语言编写的静态库或者动态库,也是不可以直接调用的。
209
+
210
+ 那么一个C++工程如何调用C语言编写的代码呢?一个C工程又如何调用C++语言编写的代码呢?
211
+
212
+ 这实际上是一个代码可移植问题,这里就需要用到条件编译和extern "C"了。
213
+
214
+ C语言中并没有重载和类这些特性,故并不像C++那样print(int i),会被编译为_print_int,而是直接编译为_print等。因此如果直接在C++中调用C的函数会失败,因为连接是调用C中的 print(3)时,它会去找_print_int(3)。因此extern "C"的作用就体现出来了。
215
+
200
216
201
217
如果在C++中编写一个程序需要用到C的库,那该怎么办呢?如果这样声明一个C函数:
202
218
``` c
203
219
float f (int a, char b);
204
220
```
205
- C++的编译器就会将这个名字变成像_f_int_char之类的东西以支持函数重载(和类型安全连接)。然而,C编译器编译的库一般不做这样的转换,所以它的内部名为_f。这样,连接器无法解释C++对f()的调用。
221
+ C++的编译器就会将这个名字变成像_f_int_char之类的东西以支持函数重载(和类型安全连接),而C中是不支持函数重载的,所以不会修改函数的名字 。然而,C编译器编译的库一般不做这样的转换,所以它的内部名为_f。这样,连接器无法解释C++对f()的调用。
206
222
C++中提供了一个替代连接说明(alternate linkage specification),它是通过重载extern关键字来实现的。
207
223
extern后跟一个字符串来指定想声明的函数的连接类型,后面是函数声明。
208
224
```c++
209
225
extern "C" float f(int a, char b);
210
226
```
211
- 这就告诉编译器f()是C连接,这样就不会转换函数名。标准的连接类型指定符有"C"和"C++"两种,如果有一组替代连接的声明,可以把它们放在花括号内:
227
+ 这就告诉编译器f()是C连接,这样就不会转换函数名。
228
+ 标准的连接类型指定符有"C"和"C++"两种,如果有一组替代连接的声明,可以把它们放在花括号内:
212
229
``` c++
213
230
extern "C" {
214
231
float f(int a, char b);
@@ -577,11 +594,11 @@ extern const int bufSize; // 与file_1.cc中定义的bufSize是同一个
577
594
file_1.h头文件中的声明也由extern做了限定,其作用是指明bufSize并非本文件所独有,它的定义将在别处出现。
578
595
579
596
#### const引用
580
- 可以把引用绑定到const对象上,就像绑定到其他对象上一样,我们称之为对常量的引用(reference to const)。
581
- 与普通引用不同的是,对常量的引用不能被用作修改它所绑定的对象。
597
+ const引用是指向const对象的引用。
582
598
``` c++
583
599
const int ci = 1024 ;
584
600
const int &r1 = ci; // 正确:引用及其对应的对象都是常量
601
+ int &ref2 = ci; // 错误:const对象的引用必须是const引用
585
602
void Start::show () const {...}
586
603
```
587
604
这里的const表示`const Start* this`,而this指向调用的对象。
@@ -598,6 +615,18 @@ const Stock& Stock::topval(const Stock& s) const {
598
615
该方法返回对this或s的引用。因为this和s都被声明为const,所以函数不能对他们进行修改,这意味着返回的引用也必须被声明为const。
599
616
注意,如果函数将参数声明为指向const的引用或指针,则不能将该参数传递给另一个函数,除非后者也确保了参数不会被修改。
600
617
618
+
619
+ ##### const修饰方法或对象
620
+ const修改函数时可以构成重载。
621
+ ``` c++
622
+ void dis () const ;
623
+
624
+ void dis ();
625
+ ```
626
+ - const修饰函数,是从函数的层面,该函数内部不能修改成员数据。
627
+ - const修饰对象,是从对象层面不修改数据,只能调用const成员函数。const对象只能调用const成员函数。非const成员对象,优先调用非const成员函数,若无,则可调用const成员函数。
628
+
629
+
601
630
##### 指针和const
602
631
与引用一样,也可以令指针指向常量或非常量。
603
632
指向常量的指针(pointer to const)不能用于改变其所指对象的值。要想存放常量对象的地址,只能使用指向常量的指针:
@@ -633,6 +662,9 @@ const int *p = &a; // 常量指针:指针的指向可以修改,但是指针
633
662
*p = 20 ; // 错误,指针指向的值不可以改
634
663
p = &b; // 正确,指针指向可以改
635
664
```
665
+ 一个简单的记法就是:
666
+ ` const int *p ` ,那const就是修饰的 ` *p ` ,也就是指针指向的值是不能修改的。
667
+
636
668
637
669
###### 指针常量(const修饰常量)
638
670
``` c++
@@ -641,6 +673,9 @@ int * const p = &a; //指针的指向不可以改,但是指针指向的值可
641
673
p = &b; // 错误,指针指向不可以改
642
674
```
643
675
676
+ 一个简单的记法就是:
677
+ ` int * const p = &a; ` ,那const修饰的是` p ` ,也就是指针是不能修改的。那p就是一个常量,常量是必须要初始化的。
678
+
644
679
###### const即修饰指针,又修饰常量
645
680
``` c++
646
681
const int * const p = &b; // 指针的指向和指针指向的值都不可以改
@@ -966,7 +1001,7 @@ class Box {
966
1001
static int height;
967
1002
static int volume();
968
1003
};
969
-
1004
+ // static的属性不能在类内初始化,必须在类外初始化
970
1005
int Box::length = 5;
971
1006
int Box::width = 3;
972
1007
int Box::height = 2;
@@ -979,6 +1014,12 @@ int main() {
979
1014
return 0;
980
1015
}
981
1016
```
1017
+ static在类内部用来实现类对象间的数据共享。在生成对象的时候,普通数据成员才有空间。
1018
+ 而static成员在类指明的时候就已经开辟了空间。
1019
+ static数据成员,即属于类,也属于对象,但终归还是属于类。
1020
+ - static变量初始化
1021
+ 类内定义,类外初始化。 type类名::变量名=初始值
1022
+
982
1023
983
1024
##### 强制类型转换
984
1025
```c++
0 commit comments