c++ primer 19th 特殊工具与技术
一、控制内存分配
new表达式与operator new函数
string *sp = new string("hello world");//分配并初始化一个string对象 string *arr = new string[10];//分配10个默认初始化的string对象 delete sp;//销毁*sp,然后释放sp指向额内存空间 delete[] arr;//销毁数组中的元素,然后释放对应的内存空间
当我们使用一条new表达式时:
实际执行了三步操作.第一步,new表达式调用一个operator new(或者operator new[])的标准库函数。该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或者对象的数组)。第二步,编译器运行相应的构造函数以构造这些对象,并为其传入初始值。第三步,对象被分配了空间并构造完成,返回一个指向该对象的指针。
当我们使用一条delete表达式删除一个动态分配的对象时:
实际执行了两步操作。第一步,对sp所指的对象或者arr所指的数组中的元素执行对应的析构函数。第二步,编译器调用名为 operator delete(或者operator delete[])的标准库函数释放内存空间。
如果程序希望控制内存分配的过程, 则它们需要定义自己的operator new函数和operator delete函数。即使标准库中已经存在这两个函数的定义,我们依旧可以定义自己的版本。
一条new表达式的执行过程总是先调用operator new函数以获取内存空间,然后在得到的内存空间中构造对象。与之相反,一个delete表达式的执行过程总是先销毁对象,然后调用operator delete函数释放对象所占的空间。
malloc函数与free函数
malloc函数接受一个表示待分配字节数的size_t,返回指向分配空间的指针或者返回0以表示分配失败。free函数接受一个void*,它是malloc返回的指针的副本,free将相关内存返回给系统。调用free(0)没有任何意义。
编写operator new 和 operator delete的一种简单方式,其他版本与之类似:
void *operator new(size_t size) {if(void *mem = malloc(size)){return mem;}else{throw bad_alloc();} } void operator delete(void *mem) noexcept {free(mem); }
显示析构函数调用
string *sp = new string("hello world"); sp->~string();
调用析构函数会销毁对象,但是不会释放内存。
二、运行时类型识别
dynamic_cast运算符的使用形式:
dynamic_cast<type*>(e)
dynamic_cast<type&)(e)
dynamic_cast<type&&)(e)
第一种形式中,e必须是一个有效的指针;在第二种形式中,e必须是一个左值;在第三种形式中,e不能是左值。
e的条件:必须是目标type的共有派生类、e的类型是目标type的共有基类或者e的类型就是目标type的类型。
返回:如果符合,则转换成功。否则如果转换的是指针类型并且失败了,则结果为0,如果是引用类型并且失败了,则抛出一个bad_cast异常。
指针类型的dynamic_cast
if(Derived *dp = dynamic_cast<Derived*>(bp)) else
我们可以对一个空指针执行dynamic_cast,结果是所需类型的空指针。
引用类型的dynamic_cast
void f(const Base &b) {try{const Derived &b = dynamic_cast<const Derived&>(b);}catch(bad_cast){} }
typeid运算符
它允许程序向表达式提问:你的对象是什么类型?
使用typeid运算符:
通常情况下,我们使用typeid比较两条表达式的类型是否相同,或者比较一条表达式的类型是否与指定类型相同:
Derived *dp = new Dericed; Base *bp = dp; if(typeid(*bp) == typeid(*dp)) {//指向同一类型的对象 } if(typeid(*bp) == typeid(Derived)) {//bp实际指向Derived对象 }
下面的检查永远不执行:bp的类型时指向Base的指针
if(typeid(bp) == typeid(Derived)) { }
当typeid作用于指针(而非指针所指的对象),返回的结果是该指针的静态编译时类型。如果p是一个空指针,则typeid(*p)将抛出一个名为bad_typeid的异常。
type_Info类
- t1 == t2如果对象t1和t2 表示相同类型,返回true,否则false
- t1 != t2 如果type_info对象t1和t2表示不同的类型,返回true,否则false
- t.name() 返回一个C风格字符串,表示类型名字的可打印形式。
- t1.before(t2) 返回一个bool值,表示t1是否位于t2之前。
int arr[10]; Derived d; Base *p = &d; cout << typeid(42).name() << endl; cout << typeid(arr).name() << endl; cout << typeid(Sales_data).name() << endl; cout << typeid(std::string).name() << endl; cout << typeid(p).name() << endl; cout << typeid(*p).name() << endl;
结果如下:i,A10_i,10Sales_data,Ss,P4Base,7Derived
三、枚举类型
(非)限定作用域枚举类型
#include<bits/stdc++.h> using namespace std; enum class MyEnum {p1 = 1,p2 }; int main() {MyEnum myEnum = MyEnum::p1;cout << (int)myEnum << endl;//一定要加int }
没有class就是不限定作用域
#include<bits/stdc++.h> using namespace std; enum class MyEnum {p1 = 1,p2 }; int main() {enum color {p1 = 1,p2};color p3 = p2;cout << p3 << endl; }
枚举类型的前置声明
enum intV : unsigned long long;//不限定作用域的前置声明 enum class open_modes; //默认int
四、类成员指针
首先定义一个Screen类
#include<bits/stdc++.h>
using namespace std;
class Screen
{
public:Screen(string str){contents = str;}void f1(){cout << "1" << endl;}static const string Screen::*data(){return &Screen::contents;}
public:std::string contents;
};
数据成员指针
Screen sc("hello world!"); auto pdata = &Screen::contents;//pdata声明成一个"指向Screen类的const string成员的指针”只能读取它所指的成员,而不能向它写入内容 cout << sc.*pdata << endl;
返回数据成员指针的函数
Screen sc("hello world!"); const string Screen::*d = Screen::data(); auto s = sc.*d;//要想使用pdata,必须把它绑定到Screen类型的对象上 cout << s << endl;
成员函数指针
Screen sc("hello world!"); auto pmf = &Screen::f1; (sc.*pmf)();//括号必不可少!
成员指针函数表
#include<bits/stdc++.h> using namespace std; class Screen { public:Screen(string str){contents = str;}void f1(){cout << "1" << endl;}static const string Screen::*data(){return &Screen::contents;}Screen& home();Screen& forward();Screen& back();Screen& up();Screen& down(); public:using Action = Screen& (Screen::*)();enum Directions{Home,FORWARD,BACK,UP,DOWN};std::string contents;Screen& Screen::move(Directions cm){return (this->*Menu[cm])();} public:static Action Menu[]; //函数表 }; int main() { Screen myScreen("hello world!");myScreen.move(Screen::Home);myScreen.move(Screen::DOWN); }
初始化函数表:
Screen::Action Screen::Menu[] = {&Screen::home,&Screen::forward,&Screen::back,&Screen::up,&Screen::down }
将成员函数用作可调用对象
使用mem_fn生成一个可调用对象
vector<string> vec; vec.push_back(""); cout << count_if(vec.begin(),vec.end(),mem_fn(&string::empty)) << endl; //1
五、union
union是一种特殊的类。一个union可以有多个数据成员,但是在任意时刻只有一个数据成员可以有值。当我们给union的某个成员赋值之后,该union的而其他成员就变成未定义的状态了。分配给一个union对象的存储空间至少要能容纳它的最大的数据成员。
#include<bits/stdc++.h> using namespace std; union Token {char cval;int ival;double dval; }; int main() { Token fir = {'a'};// Token sec;// Token *pt = new Token;cout << fir.cval << endl;fir.ival = 10;cout << fir.ival << endl;cout << fir.cval << endl;//木有了 }
union可以为其成员指定public、protected和private等保护标记。默认情况下,union的成员都是共有的,这一点与struct相同。
union可以定义包括构造函数和析构函数在内的成员函数。但是由于union既不能继承自其他类,也不能作为基类使用,所以在union中不能含有虚函数。
匿名union,可直接访问它的成员
#include<bits/stdc++.h> using namespace std;int main() { union {char cval;int ival;double dval;};cval = 'c';ival = 42;cout << cval << endl;cout << ival << endl; }
转载于:https://www.cnblogs.com/Jawen/p/11151046.html
c++ primer 19th 特殊工具与技术相关推荐
- 第19章 特殊工具与技术【C++】
第19章 特殊工具与技术 到此你会感觉C++越来越离谱,不好好想着解决问题,语法与特性先成为了一大问题.只能说太复杂了,上手难度较高. 本章分别从,控制内存分配.运行时类型识别.枚举类型.类成员指针. ...
- C++_Primer_学习笔记_第十九章(特殊工具和技术)
第十九章(特殊工具与技术) /1.控制内存分配 1).不能直接应用标准内存管理机制. 某一些应用程序需要自定义内存分配的的细节,比如使用关键字new将对象放置在特定的内存空间中. 为了实现这一个目的, ...
- C++Primer5th 第十九章 特殊工具与技术
第十九章 特殊工具与技术 19.1 控制内存分配 19.1.1 重载new和delete malloc函数与free函数 19.1.2 定位new表达式 19.2 运行时类型识别 19.2.1 dyn ...
- 37、C++ Primer 4th笔记,特殊工具与技术,类成员指针
1.成员指针(pointer to member)包含类的类型以及成员的类型.成员指针只应用于类的非static成员.static类成员不是任何对象的组成部分,所以不需要特殊语法来指向static成员 ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)异常类层次
1. 类 exception . bad_cast 和 bad_alloc 定 义 了 默 认 构 造 函 数 runtime_error 和 logic_error没有默认构造函数, 但是有一个可以 ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)typeid运算符
1. typeid运算符(typeid operator) 它允许程序向表达式提问:你的对象是什么类型? typeid表达式的形式是typeid(e),其中e可以是任意表达式或类型的名字,它操作的结果 ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)运行时类型识別RTTI
1. 运行时类型识别(run-time type identification ) 当我们将这两个运算符用于某种类型的指针或引用, 并且该类型含有虚函数时, 运算符将 使用指针或引用所绑定对象的动态类 ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)type_info 类
1. type_info 的操作 操作 描述 t1 == t2 如果type_info对象t1和t2表示同一种类型,则返回true t1 != t2 如果type_info对象t1和t2表示不同的类型 ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)typeid
1. 通常情况下使用 typeid 比较两条表达式的类型是否相同或者比较一条表达式的类型是否与指定的类型相同 Derived *dp = new Derived; Base *bp = dp; // ...
- C++ Primer 5th笔记(chap 19 特殊工具与技术)使用 RTTI
1. RTTI用处 当想为具有继承关系的类实现相等运算符时.对于两个对象来说,如果他们的类型相同并且对应的数据成员取值相同,则我们说这两个类是相等的. class Base {friend bool ...
最新文章
- NovuMind 首秀 CES,展示业界最高性能的 AI 芯片
- Js弹性漂浮广告代码
- Linux内核社区是数字军火商、斯拉夫兵工厂甚至NSA的最爱
- react-router 4.0 学习笔记
- 斗鱼赴美递交IPO招股书:拟登陆纽交所 融资5亿美金
- 用汇编的眼光看C++(之类静态变量、静态函数)
- python io密集 多线程_python多进程和多线程究竟谁更快(详解)
- 太强了!一个基于 Redis 的限流系统的设计!
- android opengl 图像同步fence创建
- 方便快速地创建新浪微博表情选择对话框——jQuery Sina Emotion
- nsight linux,NVIDIA为Nsight Systems增加Vulkan支持
- ENVI大气校正后遥感图像颜色变了及编辑头文件
- 信号调制三种方法的带宽比较
- 数据库——关系数据库规范化习题
- Microsoft Visio 专业版 2019,注意事项(bat文件乱码以及登不上Microsoft账号问题0x80190001)
- kubectl template 一个例子
- 163邮箱注册哪个好?电子邮箱怎么申请?
- throw new Error() 真实的用法和throw error 的方法
- FreeBSD服务器的安装与优化(3)
- python依据出生日期判断星座(少量代码)