标识符
extern
置于变量或函数前,以表示变量或函数的定义在别的文件中,提示编译器碰见此变量和函数时在其余模块中寻找其定义。在使用extern时候要严格对应声明时的格式。 ios
在一个源文件里定义了一个数组:char a[6];
在另一个文件里用下列语句进行了声明:extern char *a;
不能够,程序运行时会告诉你非法访问。缘由在于,指向类型T的指针
并不等价于类型T的数组
。extern char *a声明的是一个指针
变量而不是字符数组
,所以与实际的定义不一样,从而形成运行时非法访问。应该将声明改成extern char a[ ]。
现代编译器通常采用按文件编译的方式,所以在编译时,各个文件中定义的全局变量是互相不透明的。也就是说,在编译时,全局变量的可见域限制在文件内部。 程序员
extern “C”
在C++环境下使用C函数的时候,经常会出现编译器没法找到obj模块中的C函数定义,从而致使连接失败的状况,应该如何解决这种状况呢?
答案与分析: 数组
C++语言在编译的时候为了解决函数的多态问题,会将函数名和参数联合起来生成一个中间的函数名称,而C语言则不会,所以会形成连接时找不到对应函数状况,此时C函数就须要用extern “C”进行连接指定,这告诉编译器,请保持个人名称,不要给我生成用于连接的中间函数名。 函数
#pragma
预处理指令,设定编译器的状态或者是指示编译器完成一些特定的动做。 spa
#pragma message(“消息文本”)
当 编译器遇到这条指令时就在编译输出窗口中将消息文本打印出来。 指针
获取结构体偏移量 code
这个宏定义在C标准库的头文件 stddef.h 里有定义
typedef unsigned long size_t;
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
#include <iostream>
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<<s<<endl;
char c;
cin>>c;
return 0;
}
四、隐式转换 htm
第一种: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 & );
按照默认规定,只有一个参数的构造函数也定义了一个隐式转换,将该构造函数对应数据类型的数据转换为该类对象,以下面所示:
class String {
String ( const char* p );
// 用C风格的字符串p做为初始化值
//…
}
String s1 = “hello”; //OK 隐式转换,等价于String s1 = String(“hello”);
可是有的时候可能会不须要这种隐式转换,以下:
class String {
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 关键字:
class String {
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 只对构造函数起做用,用来抑制隐式转换。