标签: C++Primer 学习记录 运行时类型识别 枚举类型 类成员指针
string *sp = new string("value");
,实际执行了三步操作。
operator new
的标准库函数,来分配一块足够大的,原始的,未命名的内存空间,以便存储特定类型的对象(或者对象的数组)。delete sp;
,实际执行了两步操作。
operator delete
的标准库函数释放内存空间。operator new
和 operator delete
函数,来控制内存分配的过程。
operator new
和 operator delete
函数,也可以将它们定义为成员函数。当编译器发现一条 new表达式或 delete表达式后,将在程序中查找可供调用的 operator函数。如果被分配(释放)的对象是类类型,则查找顺序如下。
operator new
和 operator delete
函数是隐式静态的。因为 operator new
用在对象构造之前而 operator delete
用在对象销毁之后,所以这两个成员必须是静态的,而且他们不能操纵的任何数据成员。
operator new
和 operator delete
函数时,通常会用到 malloc
和 free
函数。
void *operator new(size_t size) { if (void *men = malloc(size)) return mem; else throw bad_alloc(); } void operator delete(void *mem) { free(mem); }
定位 new表达式
构造对象但是不分配内存。允许我们在一个特定的预先分配的内存地址上构造对象 new (&sval) string(s);
。创建对象但是不分配内存,而是在已有的内存块上面创建对象。用于需要反复 创建并删除的对象上,可以降低分配释放内存的性能消耗。
#include <iostream> #include <string> #include <new> using namespace std; const int BUF = 512; class JustTesting { private: string words; int number; public: JustTesting(const string & s = "Just Testing", int n = 0) { words = s; number = n; cout << words << "constructed\n"; } JustTesting() { cout << words << "destroyed\n"; } void show()const { cout << words << "," << number << endl; } }; int main() { char * buffer = new char[BUF]; JustTesting *pc1, *pc2; // 在 buffer的 0~sizeof(JustTesting)处构建对象 pc1 = new (buffer) JustTesting; // 开辟新的堆空间并构建对象 pc2 = new JustTesting("Heap1", 20); // 在 buffer的 sizeof(JustTesting)+1~2*sizeof(JustTesting)处构建对象 pc3 = new (buffer + sizeof(JustTesting)) JustTesting("Better idea",4); // 开辟新的堆空间并构建对象 pc4 = new JustTesting("Heap2", 10); // 析构对象并回收使用 new表达式开辟的空间 delete pc2; delete pc4; // 显式的调用析构函数来析构对象 pc3->~JustTesting(); pc1->~JustTesting(); // 最后再释放用于存储这些对象的空间 delete[]buffer; return 0; }
typeid(e)
,返回结果是一个常量对象的引用,该对象的类型是标准库类型 type_info
或其公有派生类型。typeid运算符可以作用于任意类型的表达式。
Derived *dp = new Derived; Base *bp = dp; // 两个指针都指向 Derived对象 // 在运行时比较两个对象的类型 if (typeid(*bp) == typeid(*dp)) { // bp和dp指向同一类型的对象 } //检查运行时类型是否是某种指定的类型 if (typeid(*bp) == typeid(Derived)) { // bp 实际指向 Derived对象 } // 注意,typeid应该作用于对象,因此我们使用*bp而非bp // 下面的检查永远是失败的: bp的类型是指向Base的指针 // 这里并不会报错,而是指针类型不可能等于对象类型 if (typeid(bp) == typeid(Derived)) { //此处的代码永远不会执行 }
type_info
类对象 t,t.name()
返回一个 C风格字符串,表示类型名字的可打印形式,类型名字的生成方式因系统而异。
.*
或->*
。
Screen myScreen, *pScreen = &myScreen; auto s = myScreen.*pdata; s = pScreen->*pdata;
.*
或者 ->*
运算符。
// 因为函数调用运算符的优先级较高,所以在声明指向成员函数的指针, // 并使用这样的指针进行函数调用时,括号必不可少 char (Screen::*pmf2)(Screen::pos, Screen::pos) const; pmf2 = &Screen::get; Screen myScreen, *pScreen = &myScreen; char c1 = (myScreen.*pmf2)(0, 0); char c2 = (pScreen->*pmf2)(0, 0);
function
。需要指明对象是否是以指针或引用的形式传入。vector<string*> pvec; function<bool (const string*)> fp = &string::empty; // fp接受一个指向 string的指针,然后使用 ->*调用 empty find_if(pvec.begin(), pvec.end(), fp);
mem_fn
。根据成员指针的类型推断可调用对象的类型,而无需用户显示的指定。生成的可定对象可以通过对象调用,也可以通过指针调用。find_if(pvec.begin(), pvec.end(), mem_fn(&string::empty));
bind
生成一个可调用对象。生成的对象既可以是指针,也可以是引用。find_if(pvec.begin(), pvec.end(), bind(&string::empty, _1));
union
是一种特殊的类,一个 union可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当给 union的某个成员赋值之后,其他成员就变成未定义的状态了。
匿名 union
是一个未命名的 union,并且在右花括号和分号之间没有任何声明。在匿名 union
的定义所在的作用域内,该 union的成员都是可以直接访问的。匿名 union
不能包含受保护的成员或私有成员也不能定义成员函数。
union { // 匿名 union char cval; int ival; double dval; }; //定义一个未命名的对象,我们可以直接访问它的成员 cval = 'c' // 为刚刚定义的未命名的匿名 union对象賦一个新值 ival = 42; // 该对象当前保存的值是 42
位域
的概念。它是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
typedef unsigned int Bit; Bit mode: 2; // mode占 2位 Bit modified: 1; // modified占 1位
volatile
**。关键字 volatile
告诉编译器不应对这样的对象进行优化。
volatile int display_register; // 该 int值可能发生改变 volatile int iax[max_size]; // iax的每个元素都是 volatile
volatile int v; // v是一个 volatile int int *volatile vip; // vip是一个 volatile指针,它指向 int volatile int *ivp; // ivp是一个指针,它指向一个 volatile int // vivp是一个 volatile指针,它指向一个 volatile int volatile int *volatile vivp; int *ip = &v; // 错误,必须使用指向 volatile的指针 ivp = &v; // 正确,ivp是一个指向 volatile的指针 vivp = &v; // 正确,vivp是一个指向 volatile的 volatile指针
链接指示
指出任意非 C++函数使用的语言。
// 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) { /* ... */ }