19 C++ 特殊工具与技术

系列文章目录



前言

该章节为扩展内容


控制内存分配

// new expression
string *sp = new string("a value");
  1. 调用operator new函数分配内存空间
  2. 编译器运行相应构造函数进行初始化
  3. 返回指向该对象的指针
delete sp;
  1. 调用析构函数
  2. 编译器调用operator delete的标准库函数释放内存空间

operator new接口和operator delete接口
在这里插入图片描述

示例:pandas 是基于NumPy 的一种工具,该工具是为了解决数据分析任务而创建的。
malloc 函数与 free函数
<cstdlib>
在这里插入图片描述

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); }

定位new表达式

new (place_address) type
new (place_address) type (initializers)
new (place_address) type [size]
new (place_address) type [size] { braced initializer list }

运行时类型时别

run-time type identification, RTTI

  • typeid运算符,用于返回表达式的类型
  • dynamic_cast运算符,用于将基类的指针或引用安全地转换成派生类的指针或引用

dynamic_cast运算符

dynamic_cast<type*>(e)
dynamic_cast<type&>(e)
dynamic_cast<type&&>(e)

typeid运算符

使用typeid运算符

Derived *dp = new Derived;
Base *bp = dp;
//在运行时比较两个对象的类型
if (typeid(*bp) == typeid(*dp)){
	// bp dp指向同一类型的对象
}
//检查运行时类型是否是某种指定的类型
if (type(*bp) == typeid(Derived)){
	//bp实际指向Derived对象
}

使用RTTI

class Base
{
	friend bool operator==(const Base&, Base&);
protected:
	virtual bool equal(const Base&) const;
};
class Derived:public Base
{
public:
	//
protected:
	bool equal(const Base&) const;
};

bool operator==(cosnt Base&lhs, const Base&rhs)
{
	return typeid(rhs) == typeid(lhs) && lhs.equal(rhs);
}

type_info类

定义在 typeinfo头文件中
在这里插入图片描述

枚举类型

//限定作用域的枚举类型
enum class/struct opem_modes {input, output, append};

//不限定作用域的枚举类型
enum color { red, yellow, green };
//未命名的、不限定作用域的枚举类型
enum { floatPrec = 6, doublePrec = 10, double_doublePrec = 10 };

类成员指针

成员指针pointer to member是指可以指向类的非静态成员的指针。
在这里插入图片描述

class Screen {
public:
	typedef std::string::size_type pos;
	char get_cursor() const {return contents[cursor];}
	char get() const;
	char get(pos ht, pos wd) const;
private:
	std::string contents;
	pos cursor;
	pos height, width;
};

数据成员指针

//pdata可以指向一个常量(非常量)Screen对象的string成员
const string Screen::*pdata;
pdata = &Screen::contents;

//使用数据成员指针
Screen myScreen, *pScreen = &myScreen;
// .*解引用pdata以获得myScreen对象的contents成员
auto s = myScreen.*pdata;
// ->*解引用pdata以获得pScreen所指对象的contents成员
s = pScreen->*pdata;

返回数据成员指针的函数

class Screen {
public:
	//data是一个静态成员,返回一个成员指针
	static const std::string Screen::*data()
		{return &Screen::contents;}
};

const string Screen::*pdata = Screen::data();

成员函数指针

char (Screen::*pmf2)(Screen::pos, Screen::pos) const;
pmf2 = &Screen::get;

char Screen::*p(Screen::pos, Screen::pos) const;	//❌非成员函数p不能使用const限定符

//使用函数成员指针
Screen myScreen, *pScreen = &myScreen;
//通过pScreen所指的对象调用pmf所指的函数
char c1 = (pScreen->*pmf)();
//通过myScreen对象将实参0,0传给
char c2 = (myScreen.*pmf2)(0, 0);

using Action = char (Sreen::*)(Screen:pos, Screen::pos) const;
Action get = &Screen::get;  //get指向Screen的get成员
// actiong接收一个Screen的引用,和一个指向Screen成员函数的指针
Screen& action(Screen&, Action = &Screen::get);

成员指针函数表

class Screen{
public:
	Screen& home();
	Screen& forward();
	Screen& back();
	Screen& up();
	Screen& down();
	using Action = Screen&(Screen::*)();
	enum Directions { HOME, FORWARD, BACK, UP, DOWN };
	Screen& move(Directions);
private:
	static Action Menu[];	//函数表
};
Screen &Screen::move(Directions cm)
{
	return (this->*Menu[cm])();	//Menu[cm]指向一个成员函数
}
Screen::Action Screen::Menu[] = {&Screen::home, 
								 &Screen::forward, 
								 &Screen::back, 
								 &SCreen::up,
								 &Screen::down };

Screen myScreen;
myScreen.move(Screen::HOME);
myScreen.move(Screen::DOWN);

将成员函数用作可调用对象

以下都定义在functional头文件中
成员指针自然不是可调用对象
使用function生成一个可调用对象

function<bool (const string&)> fcn = &string::empty;
find_if(svec.begin(), svec.end(), fcn);

使用mem_fn生成一个可调用对象

find_if(svec.begin(), svec.end(), mem_fn(&string::empty));

使用bind生成一个可调用对象

auto it = find_if(svec.begin(), svec.end(), bind(&string::empty, _1));

嵌套类

声名一个嵌套类

class TextQuery{
public:
	class QueryResult;	//嵌套类
};
class TextQuery::QueryResult{
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
	//嵌套类可以直接使用类的成员
	QueryResult(std::string, std::shared_ptr<std::set<line_no>>,
				std::shared_ptr<std::vector<std::string>>);
};

在外层类之外定义一个嵌套类

定义嵌套类的成员

TextQuery::QueryResult::QueryResult(string s,
									shared_ptr<set<line_no>> p,
									shared_ptr<vector<string>> f):
							sought(s), lines(p), file(f) { }

嵌套类静态成员定义

//QueryReuslt类嵌套在TextQuery类中
//下面的代码为QueryResult定义一个静态成员
int TextQuery::QueryResult::static_mem = 1024;

嵌套类作用域中的名字找查

//返回类型必须指明QueryResult是一个嵌套类
TextQuery::query(const string &sought) const
{
	//如没找到sought,则返回set的指针
	static shared_ptr<set<line_no>> nodata(new set<line_no>);
	//使用find而非下标以避免向wn中添加单词
	auto loc = wm.find(sought);
	if (loc == wm.end())
		return QueryResult(sought, nodata, file);
	else
		return QueryResult(sought, loc->second, file);
}

在这里插入图片描述

union:一种节省空间的类

//Token类型的对象只有一个成员,该成员的类型可能是下列类型中的任意一种
union Token(可选的){
//默认情况下成员是共有的
    char cval;
    int  ival;
    double dval;
};

Token first_token = {'a'};	//初始化cval成员
Token last_token;			//未初始化的Token对象
Token *pt = new Token;		//指向一个未初始化的Token对象的指针

union {			//匿名union
	char cval;
	int ival;
	double dval;
};	//定义一个未命名的对象,可直接访问他的成员
cval = 'c';
ival = 43;
class Token
{
public:
	//因为union含有一个string成员,所以Token必须定义拷贝控制成员
	Token(): tok(INT), ival{0} { }
	Token(const Token &t): tok(t.kok) { copyUnion(t); }
	Token &operator=(const Token&);
	//如果union含有一个string成员,则我们必须销毁它
	~Token() { if (tok == STR) sval.~string(); }
	//下面的赋值运算符负责设置union的不同成员
	Token &operator=(const std::string&);
	Token &operator=(char);
	Token &operator=(int);
	Token &operator=(double);
private:
	enum {INT, CHAR, DBL, STR} tok; //判别式
	union { //匿名union
		char cval;
		int ival;
		double dval;
		std::string sval;
	};  //每个Token对象含有一个该未命名union类型的未命名成员
	//检查判别式,然后酌情拷贝union成员
	void copyUnion(const Token&);
};
Token &Token::operator=(int i)
{
	if (tok == STR) sval.~string();
	ival = i;
	tok = INT;
	return *this;
}
Token &Token::operator=(const std::string &s)
{
	if (tok == STR)
		sval = s;
	else 
		new(&sval) string(s);
	tok = STR;
	return *this;
}
void Token::copyUnion(const Token &t)
{
	switch (t.tok){
		case Token::INT: ival = t.ival; break;
		case Token::CHAR: cval = t.cval; break;
		case Token::DBL: dval = t.dval; break;
		//要想拷贝一个string可以使用定位new表达式构造它
		case Token::STR: new(&sval) string(t.sval); break;
	}
}
Token &Token::operator=(const Token &t)
{
	//如果此对象的值式string而t的值不是,则我们必须释放原来的string
	if (tok == STR && t.tok != STR) sval.~string();
	if (tok == STR && t.tok == STR)
		sval = t.sval;
	else
		copyUnion(t);
	tok = t.tok;
	return *this;
}

局部类

局部类不能使用函数作用域中的变量

int a, val;
void foo(int val)
{
	static int si;
	enum Loc { a = 1024, b };
	//Bar是foo的局部类
	struct Bar
	{
		Loc locVal;
		int barVal;
		void fooBar(Loc l = a)
		{
			barVal = val;
			barVal = ::val;
			barVal = si;
			locVal = b;
		}
	}
}

固有的不可移植的特性

与机器相关

位域

位域在内存中的布局是与机器相关的

typedef unsigned int Bit;
class File
{
	Bit mode:2;	//mode占2位
	Bit modified:1; 	//占1位
public:
	//文件类型以八进制的形式表示
	enum modes { READ = 01, WRITE = 02, EXECUTE = 03 };
	File &open(modes);
	void close();
	void write();
	bool isReak() const;
	void setWrite();
};
void  File::write()
{
	modified = 1;
}
void File::close()
{
	if (modefied)
}
File &File::open(File::modes m)
{
	mode |= READ:
	if (m & WRITE) //
	return *this;
}
inline bool File::isRead() const { return mode & READ; }
inline void File::setWrite() { mode |= WRITE; }

volatile限定符

链接指示:extern “C”


总结

类成员指针

struct First{
    int mem=9;
    void memfunc(int a) const;
};
int First::*pmem = &First::mem;
void (First::*pfunc)(int) const = &First::memfunct;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值