本文共 4898 字,大约阅读时间需要 16 分钟。
本文为《C++ Primer》的读书笔记
当一个程序需要向其他程序或硬件设备传递二进制数据时,通常会用到位域
typedef unsigned int Bit;class File { Bit mode: 2; // mode 占 2 位 Bit modified: 1; Bit prot_owner: 3; Bit prot_group: 3; Bit prot_world: 3; // File的操作和数据成员public: // 文件类型以八进制的形式表示 enum modes { READ = 01, WRITE = 02, EXECUTE = 03 }; File &open(modes); void close(); void write(); bool isRead() const; void setWrite();};
unsigned int
中。这些二进制位是否能压缩到一个整数中以及如何压缩是与机器相关的&
)不能作用于位域,因此任何指针都无法指向类的位域void File::write(){ modified = 1; // ...}void File::close(){ if(modified) // ······ 保存内容}File &File::open(File::modes m){ mode |= READ; // 按默认方式设置READ // 其他处理 if(m & WRITE) // 如果打开了READ和WRITE // 按照读/写方式打开文件 return *this;}inline bool File::isRead() const { return mode & READ; }inline void File::setWrite() { mode |= WRITE; }
volatile
限定符不可移植特性
volatile
的确切含义与机器有关, 只能通过阅读编译器文档来理解。要想让使用了 volatile
的程序在移植到新机器或新编译器后仍然有效, 通常需要对该程序进行某些改变volatile
来告诉编译器不应对这样的对象进行优化
volatile
的使用和const
很相似
const
成员函数一样, 它也可以将成员函数定义成 volatile
的。只有 volatile
的成员函数才能被 volatile
的对象调用volatile int iax [max_size]; // iax的每个元素都是volatilevolatile Screen bitmapBuf; // bitmapBuf的每个成员都是volatilevolatile int v; // 该 int 值可能发生改变int *volatile vip; // vip是一个volatile指针,它指向intvolatile int *ivp; // ivp是一个指针, 它指向一个volatile intint *ip = &v; // 错误:必须使用指向volatile的指针ivp = &v; // 正确volatile int &rv = v; // 正确,只有当某个引用是volatile的时,我们才能使用一个volatile对象初始化该引用
合成的拷贝对 volatile
对象无效
volatile
对象或从 volatile
对象赋值。合成的成员接受的形参类型是(非volatile
) 常量引用,显然我们不能把一个非 volatile
引用绑定到一个 volatile
对象上volatile
对象,则该类必须自定义拷贝或移动操作 const volatile
引用,这样我们就能利用打意类型的 Foo
进行拷贝或赋值操作了class Foo { public: Foo(const volatile Foo&); // 从一个volatile对象进行拷贝 // 将一个volatile对象赋值给一个非volatile对象 Foo& operator=(volatile const Foo&); // 将一个volatile对象赋值给一个volatile对象 Foo& operator=(volatile const Foo&) volatile; // ...}
extern "C"
要想把C++代码和其他语言(包括C语言)编写的代码放在一起使用,要求我们必须有权访问该语言的编译器,并且这个编译器与当前的C++编译器是兼容的
extern
, 后面是一个字符串字面值常量以及一个 “普通的” 函数声明。其中的字符串字面值常品指出了编写函数所用的语言。编译器应该支持对C语言的链接指示// 可能出现在 C++ 头文件中的链接指示// 单语句链接指示extern "C" size_t strlen(const char *);// 复合语句链接指示// 花括号中声明的函数名字就是可见的,就好像在花括号之外声明的一样extern "C" { int strcmp(const char*, const char*); char *strcat(char*, const char*);}// 多重声明的形式可以应用于整个头文件// 链接指示可以嵌套,因此如果头文件包含带自带链接指示的函数,则该函数的链接不受影响extern "C" { #include // 操作c风格字符串的c函数}
C++从C语言继承的标准库函数可以定义成C函数,但并非必须:决定使用C还是C++实现C标准库,是每个C++实现的事情
extern "C"
函数的指针// pf指向一个c函数,该函数接受一个int返回void// 当我们使用pf调用函数时,编译器认定当前调用的是一个C函数extern "C" void (*pf) (int);
void (*pf1) (int); // 指向一个C++函数extern "C" void (*pf2) (int); // 指向一个c函数pf1 = pf2; // 错误: pf1和pf2的类型不同
// f1是一个 c 函数, 它的形参是一个指向 c 函数的指针extern "C" void f1(void(*) (int));
// FC是一个指向c函数的指针extern "C" typedef void FC(int);// f2是一个C++函数, 该函数的形参是指向c函数的指针void f2(FC *);
// calc 函数可以被 C 程序调用extern "C" double calc(double dparm) { /* ... */ }
对链接到C的预处理器的支持
__cplusplus
(两个下画线)。利用这个变量, 我们可以在编译C++程序的时候有条件地包含进来一些代码:#ifdef __cplusplus// 正确:我们正在编译C++程序extern "C"#endifint strcmp(const char*, const char*);
// 错误: 两个extern "C"函数的名字相同extern "C" void print(const char*);extern "C" void print(int);
class SmallInt { /* ... */ };class BigNum { /* ... */ };// c函数可以在C或C++程序中调用// C++函数重载了该函数, 可以在c++程序中调用extern "C" double calc(double);extern SmallInt calc(const SmallInt&); // 使用了类类型形参的C++函数只能在C++程序中调用extern BigNum calc(const BigNum&);
转载地址:http://peih.baihongyu.com/