CppPrimer笔记 Chapter19 特殊工具与技术
2017-03-14 23:22
363 查看
CppPrimer笔记 Chapter19 特殊工具与技术
标签: CppCppPrimer笔记 Chapter19 特殊工具与技术
控制内存分配191
运行时类型识别RTTI192
枚举类型193
类成员指针194
嵌套类195
union类型196
局部类197
固有的不可移植的特性198
控制内存分配(19.1)
可以自定义operator new但不能改变
new 运算符
对象的new与delete为隐式静态的的,而且不能操纵类的任何数据成员
调用
void *operator new(size_t)传入对象字节数.
调用
void *operator new[](size_t)传入数组中所有元素所需空间
定位new如下,不分配任何内存,只是单纯返回指针实参并由new表达式在指定的地址初始化对象
new(place_add)type[size]{braced initializer list
调用析构函数会销毁对象,但不会释放内存
明确 构造,析构 销毁内存,释放内存 之间的区别 可查找 RAII机制
运行时类型识别(RTTI)(19.2)
由typeid(返回表达式类型)与
dynamic_cast(将基类指针或引用安全地转换成派生类指针或引用)实现
特别适用于:用基类指针或引用执行某个非虚函数的派生类操作.
dynamic_cast使用:
dynamic_cast<type*>(e)e必须为有效指针
dynamic_cast<type&>(e)e必须为左值
dynamic_cast<type&&>(e)e必不能为左值
只允许:
e是type的公有派生类(向上转换)
e是type的公有基类(向下转换,需要指向派生类的基类指针)
e与type相同
这三种转换.
若指针转换失败,则是0,引用转换失败,抛出异常
bad_cast
typeid用于返回表达式的类型.那么可以在发生了指针上转型等过程中判断指向的对象是否相同
dp = new Derived; Base*bp = dp; if (typeid(*bp) == typeid(*dp)) { cout << "bp and dp point to same obj" << endl; } else { cout << "not same obj" << endl; }
利用RTTI实现继承成体系中
==
由于使用虚继承体系,基类引用无法访问派生类中特有的对象
class Base{ friend bool operator==(const Base&, const Base&); public: int b; protected: virtual bool equal(const Base&)const; }; bool Base::equal(const Base &rhs) const { return this->b == rhs.b; } class Derived : public Base{ public: string d; protected: bool equal(const Base&)const override; }; bool Derived::equal(const Base &rhs) const { auto r = dynamic_cast<const Derived&>(rhs); return this->b == r.b && this->d == r.d; } bool operator==(const Base&lhs, const Base&rhs) { //类型不同则返回false,否则调用equal return typeid(lhs) == typeid(rhs) && lhs.equal(rhs); }
type_info类仅能通过
typeid运算符创建,用于对象类型的比较等.
void demo_type_info() { int arr[10]; Derived d; Base*p = &d; cout << typeid (42).name() << endl << typeid (arr).name() << endl << typeid (string).name() << endl << typeid (p).name() << endl << typeid(*p).name()<<endl; }
枚举类型(19.3)
enum Tokens{INLINE = 128,VIRTUAL = 129}; //Tokens这样的全局枚举,会自动提升为int,注释第一个函数也不会报错 void ff(Tokens){ cout << "ff_Tokens" << endl; } void ff(int){ cout << "ff_int" << endl; } void ff(unsigned char){ cout << "ff_unsigned_char" << endl; } void demo_enum() { //前置声明 enum intValues :unsigned long long;//不限定作用域,必须制定成员类型 enum class peppers;//限定作用域的可以使用默认成员类型Int enum color{ red, yellow, green};//没有class或struct,为全局的 //enum stoplight{red,yellow,green}; 重定义枚举成员 enum class peppers{red=5,yellow,green=9}; color eyes = green; //peppers p = green; //error:peppers的枚举成员不在有效的作用域中, //color::green在,但类型错误 color har = color::red; peppers p2 = peppers::red; //默认情况下.枚举类型从0开始,之后成员为之前的枚举成员的值加1 int x = yellow;//x = 1 cout << x << endl; int y = (int)peppers::yellow;//限定作用域的枚举类型不会进行隐式转换 cout << y << endl; enum intValues :unsigned long long{ charTyp = 255, shortTyp = 65535, intTyp = 65535, longTyp = 4294967295UL, long_longTyp = 18446744073709551615ULL, }; Tokens curTok = INLINE; ff(128); ff(INLINE); ff(curTok); unsigned char uc = VIRTUAL; ff(VIRTUAL); ff(uc); }
类成员指针(19.4)
初始化时,我们令其指向类的某个成员,但不指定该成员所属的对象,直到使用成员指针时,才提供成员所属对象使用数据成员指针
//pdata可以指向一个常量(非常量)Screen对象的string成员 const string Screen::*pdata; //利用返回数据成员指针的函数,用于获取私有类 pdata = Screen::data(); Screen myScreen, *pScreen = &myScreen; //使用数据成员指针 auto s = myScreen.*pdata;//' ' auto s2 = pScreen->*pdata;//' ' cout << s << endl; cout << s2 << endl;
成员函数与相应指针之间不像普通函数可以自动转换
使用成员函数指针
//调用运算符前括号不可少,由于调用运算符优先级高于指针向成员运算符的优先级 char c1 = (pScreen->*pmf)(); char c2 = (myScreen.*pmf2)(0, 0); //使用别名 using Action = char(Screen::*)(Screen::pos, Screen::pos)const; Action get = &Screen::get; Screen& action(Screen&, Action = &Screen::get); //成员函数指针表 myScreen.move(Screen::HOME); myScreen.move(Screen::DOWN);
成员指针并不是可调用对象,利用function,mem_fn或bind产生可调用对象,实际上还是自动地在对象上调用函数指针
vector<string*>pvec; //function< bool (const string*) > fp = &string::empty; //fp 接受一个指向string的指针, 然后使用->*调用empty //相当于if(((*it)->*p())it为一内部迭代器 //find_if(pvec.begin(), pvec.end(), fp); //利用mem_fn可以从成员指针类型推断可调用对象类型 auto f = mem_fn(&string::empty); find_if(pvec.begin(), pvec.end(), mem_fn(&string::empty)); f(*pvec.begin()); f(pvec[0]); //使用bind生产可调用对象 auto it = find_if(pvec.begin(), pvec.end(), bind(&string::empty, _1));
嵌套类(19.5)
嵌套类的名字在外层作用域中是可见的.二者相互之间没有特殊的访问权限嵌套类的静态成员定义将位于外层作用域之外
外层类的对象与嵌套类的对象没有任何关系
union类型(19.6)
不能含有引用类型的成员没有继承特性(不可做派生类,基类,无虚函数)
由于为
union的一个数据成员赋值会令其他数据成员变成未定义的状态,不可访问
匿名的
union视为一个当前作用域内可直接访问的对象.里面的对象可直接使用,可以认为是许多已定义了的对象共享一块内存.同时,不能包含受保护的成员或私有成员.
类中的union含有类类型成员时,必须自己显示进行释放,拷贝,赋值操作.
局部类(19.7)
局部类所有成员,包括函数都必须完整定义在类的内部,不允许声明静态数据成员.局部类只能访问外层作用域定义的类型名,静态变量与枚举成员.普通的局部变量不能被该局部类使用.
局部类内的嵌套类也是局部类
固有的不可移植的特性(19.8)
类可将(非静态)(一般为无符号数)数据成员定义成位域,一个位域中含有一定数量的二进制位.取地址符
&不能用于位域
volatile表明它可能在程序控制或检测之外被改变.编译器不应该对这样的对象进行优化. 因而它其实与
const也不冲突
voltile限定符行为很像
const.比如
volatile int v; volatile int*ivp = &v;
//error int *ip = &v; //必须使用指向volatile的指针
但有一个重要区别:
我们不能使用合成的拷贝/移动构造函数与赋值运算符初始化
volatile对象或从
volatile对象赋值.
只有
voltile函数才能被
volatile对象调用
链接指示来指出任意非C++函数所用的语言.
编译器检查其调用方式与处理普通的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<string.h> }
链接指示对整个声明有效,也就是对函数而言,返回类型,形参等都是C的.它也不能使用C++中的类与对象.
C支持重载,因而一组重载中只会有一个是C的.凡是C不支持的那么都是不能使用的.
相关文章推荐
- 36、C++ Primer 4th笔记,特殊工具与技术,运行时类型识别
- 37、C++ Primer 4th笔记,特殊工具与技术,类成员指针
- C++ Primer 学习笔记_106_特殊工具与技术 --局部类
- 39、C++ Primer 4th笔记,特殊工具与技术,联合(union)
- 40、C++ Primer 4th笔记,特殊工具与技术,不可移植特征
- 34、C++ Primer 4th笔记,特殊工具与技术,优化内存分配(1)
- 38、C++ Primer 4th笔记,特殊工具与技术,嵌套类
- C++ primer第二次阅读学习笔记(第18章:特殊工具与技术:运行时类型识别、extern。。。)
- .C++ primer第二次阅读学习笔记(第18章:特殊工具与技术:优化内存分配)
- C++ Primer 学习笔记_99_特殊工具与技术 --优化内存分配[续1]
- C++ Primer 学习笔记_98_特殊的工具和技术 --优化内存分配
- C++ Primer 学习笔记_107_特殊工具与技术 --固有的不可移植的特征[上]
- C++primer阅读笔记---------特殊工具与技术
- C++primer第五版笔记-第十九章特殊工具与技术
- C++Primer学习笔记103 特殊工具与技术 类成员指针
- C++笔记(5)-特殊工具与技术
- C++ Primer 学习笔记_102_特殊工具与技术 --运行时类型识别[续]
- C++ Primer 学习笔记_100_特殊工具与技术 优化内存分配[续2]
- C++ Primer 学习笔记_105_特殊工具与技术 --联合:节省空间的类
- 35、C++ Primer 4th笔记,特殊工具与技术,优化内存分配(2)