标识符
extern
置于变量或函数前,以表示变量或函数的定义在别的文件中,提示编译器遇见此变量和函数时在其他模块中寻找其定义。在使用extern时候要严格对应声明时的格式。
在一个源文件里定义了一个数组:char a[6];
在另外一个文件里用下列语句进行了声明:extern char *a;
不可以,程序运行时会告诉你非法访问。原因在于,指向类型T的指针 并不等价于类型T的数组 。extern char *a声明的是一个指针 变量而不是字符数组 ,因此与实际的定义不同,从而造成运行时非法访问。应该将声明改为extern char a[ ]。 现代编译器一般采用按文件编译的方式,因此在编译时,各个文件中定义的全局变量是互相不透明的。也就是说,在编译时,全局变量的可见域限制在文件内部。
在C++环境下使用C函数的时候,常常会出现编译器无法找到obj模块中的C函数定义,从而导致链接失败的情况,应该如何解决这种情况呢?
答案与分析:
C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,因此会造成链接时找不到对应函数情况,此时C函数就需要用extern “C”进行链接指定,这告诉编译器,请保持我的名称,不要给我生成用于链接的中间函数名。
#pragma
预处理指令,设定的状态或者是指示编译器完成一些特定的动作。
当 遇到这条指令时就在编译输出窗口中将消息文本打印出来。
获取结构体偏移量
这个宏定义在C标准库的头文件 stddef.h 里有定义
typedef unsigned long size_t;
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#include using namespace std; struct test{ int a; int b; char c; int d;};#define FIND(structTest,e) (size_t) &(((structTest*)0)->e)int main(){ size_t s = FIND(test,b); //test t; cout< < >c; return 0;}
4、隐式转换
第一种:classB: public A { …}
B公有继承A,可以是间接公有继承,当把B的对象赋值给A,会发生隐式转换。
(待求证,保护继承、私有继承、B是A的成员能否发生转换?)
第二种:
classB:{
OperatorA();
….
}
转换constructor。类B实现了隐式转化为类A;compiler会在需要的时候自动调用该函数发生类型转换,如果想要在代码中显式的调用转换函数才能发生类型转化,可以定义explicit operator A()
第三种:
class A{
A (const B &)
}
A实现了一个个non-explicit的构造函数,参数为B(还可以带其他的有缺省值的参数)
第四种:A&operator =(const B & )
注意:对于类之间的公有继承总可以把子类转化为父类,只是把派生类对象切割为基类对象即可。
注意2:上述第二种和第三种方法同时存在一个程序中,应该注意这样的调用:
f(const A &);
B b;
f(b)则会产生调用的二义性。
注意3:如果不想使用隐式生成的函数(当然这些函数一般是缺省构造函数、copy构造函数和赋值构造函数),就要把它显式的禁止;对于一般的转换constructor可以添加explicit明确的要求显式的调用,compiler不能自动发生隐式转换。如:
Private:
A &operator = (const B &);
A (const A & );
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,如下面所示:
String ( const char* p );
// 用C风格的字符串p作为初始化值
String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(“hello”);
String ( int n ); //本意是预先分配n个字节给字符串
String ( const char* p );
// 用C风格的字符串p作为初始化值
String s2 ( 10 ); //OK 分配10个字节的空字符串
String s3 = String ( 10 ); //OK 分配10个字节的空字符串
String s4 = 10; //编译通过,也是分配10个字节的空字符串 String s5 = ‘a’; //编译通过,分配int(‘a’)个字节的空字符串 s4 和s5 分别把一个int型和char型,隐式转换成了分配若干字节的空字符串,容易令人误解。
为了避免这种错误的发生,我们可以声明显示的转换,使用
explicit 关键字:
explicit String ( int n ); //本意是预先分配n个字节给字符串
String ( const char* p );
// 用C风格的字符串p作为初始化值
加上
explicit ,就抑制了String ( int n )的隐式转换,
String s2 ( 10 ); //OK 分配10个字节的空字符串
String s3 = String ( 10 ); //OK 分配10个字节的空字符串
String s4 = 10; //编译不通过,不允许隐式的转换 String s5 = ‘a’; //编译不通过,不允许隐式的转换 因此,某些时候,
explicit 可以有效得防止构造函数的隐式转换带来的错误或者误解
----------------------------------------------------------
explicit 只对构造函数起作用,用来抑制隐式转换。如:
class A {
A(int a);
};
int Function(A a);
当调用 Function(2) 的时候,2 会隐式转换为 A 类型。这种情况常常不是程序员想要的结果,所以,要避免之,就可以这样写:
class A {
explicit A(int a);
};
int Function(A a);
这样,当调用 Function(2) 的时候,编译器会给出错误信息(除非 Function 有个以 int 为参数的重载形式),这就避免了在程序员毫不知情的情况下出现错误。
总结:
explicit 只对构造函数起作用,用来抑制隐式转换。