c++primer之特殊工具与技术

一、当使用一条new表达式时,实际执行了3步操作:

1、new表达式调用一个名为operator new(或者operator new[])的标准库函数,该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象

2、编译器运行相应的构造函数以构造这些对象,并为其传入初始值

3、对象被分配了空间并构造完成,返回一个指向该对象的指针

二、当使用一条delete表达式删除一个动态分配的对象时,实际指向了2步操作:(delete p|delete []arr)

1、对p所指的对象或arr所指的数组中的元素执行对应的析构函数

2、编译器调用名为operator delete(或operator delete[])的标准库函数释放内存空间

三、如果希望控制内存分配的过程,则需要自定义operator new函数和operator delete函数

四、因为operator new用在对象构造之前,operator delete用在对象销毁之后,所以这2个成员必须时静态的,而且它们不能操作类的任何数据成员

五、对于operator new函数或者operator new[]函数,它的返回类型时void*,第一个形参必须是size_t且该形参不能含有默认实参。当编译器调用operator new时,把存储指定类型对象所需的字节数传给size_t参数;当调用operator new[]时,传入函数的则是存储数组中所有元素所需的空间

六、void *operator new(size_t, void*)步允许重新定义, 当仅通过一个地址值调用时使用,该函数不分配任何内存,只是简单的返回指针实参

七、对于operator delete函数或者operator delete[]函数,它的返回类型必须时void,第一个形参的类型必须时void*

八、malloc函数接受一个表示待分配字节数的size_t,返回指向分配空间的指针或者返回0以表示分配失败

九、free函数接受一个void*,它时malloc返回的指针的副本,free将相关内存返回给系统,调用free(0)没有任何意义

十、对于operator new分配的内存空间无法使用construct函数构造对象

十一、运行时类型识别(RTTI)的功能由2个运算符实现:

1、typeid运算符,返回表达式的类型

2、dynamic_cast运算符,将基类的指针或引用安全的转换成派生类的指针或引用

十二、dynamic_cast<type*>(e);dynamic_cast<type&>(e);dynamic_cast<type&&>(e); e的类型必须符合3个条件中任意一个:

1、e的类型时目标type的公有派生类

2、e的类型时目标type的公有基类

3、e的类型就是目标type的类型

十三、如果一条dynamic_cast语句的转换目标是指针类型并且失败了,返回结果0; 如果转换目标是引用类型并且失败了,则抛出bad_cast异常

十四、typeid表达式的形式是typeid(e)。e可以是任意表达式或类型的名字。typeid操作的结果是一个常量对象的引用,该对象的类型是标准库类型type_info或type_info的公有派生类型

十五、如果表达式是引用,则typeid返回该引用所引用对象的类型;如果是数组,则得到的结果是数组类型而非指针类型

十六、当运算对象步属于类类型或者是一个不包含任何虚函数的类时,typeid运算符指示的是运算对象的静态类型。当运算对象是定义了虚函数的类的左值时,typeid的结果直到运行时才求得

十七、typeid(*p)如果p是一个空指针,则抛出bad_typeid异常

十八、type_info没有默认构造函数,且它的拷贝和移动构造函数以及赋值运算符都被定义成删除的,因此无法定义或拷贝type_info类型的对象,也不能为type_info类型的对象赋值。创建type_info对象的唯一途径是使用typeid运算符

十九、枚举属于字面值常量类型

二十、枚举包含: 限定作用域的枚举类型和不限定作用域的枚举类型。 定义限定作用域的枚举类型: 使用关键字enum class或enum struct,随后是枚举类型名字以及花括号括起来的以逗号分隔的枚举成员

二一、在限定作用域的枚举类型, 在枚举类型的作用域外是不可访问的

二二、枚举成员是const的,所以在初始化枚举成员时提供的初始值必须是常量表达式

二三、一个不限定作用域的枚举类型的对象或枚举成员自动的转换成整型

二四、新标准中,可以在enum的名字后加上冒号以及该enum中使用的类型来指定枚举成员的类型:enum intValues : unsigned long long {shrotTyp = 65535, intTyp = 65535}

二五、默认情况下,限定作用域的enumerate成员类型是int。不限定作用域的枚举类型不存在默认类型

二六、类成员指针是可以指向类的非静态成员的指针。一般情况下,指针指向一个对象,但成员指针指示的是类的成员,而非类的对象

二七、成员指针必须包含成员所属的类,在*之前添加类名作用域运算符以表示当前定义的指针可以指向类的成员: const string Foo::*data;

二八、(.*)和(->*)2个运算符可以解引用指针并获得该对象的成员

二九、指向成员函数的指针需要指定目标函数的返回类型和形参列表。如果成员函数是const成员或引用成员,则需要将const限定符或引用限定符包含进来

三十、在成员函数和指向该成员的指针之间不存在自动转换

三一、成员指针不是一个可调用对象,这样的指针不支持函数调用运算符,所以不能直接将一个指向成员函数的指针传递给算法。 可以使用function、mem_fn、bind生成一个可调用对象

三二、嵌套类是一个独立的类,与外层类基本没什么关系。外层类的对象和嵌套类的对象是相互独立的

三三、一个union可以有多个数据成员,但任意时刻只有一个数据成员可以右值。当给union的某个成员赋值后,该union的其他成员九变成未定义的状态了

三四、union不能含有引用类型的成员

三五、union可以定义包括构造函数和析构函数在内的成员函数,但union即不能继承自其他类,也不能作为基类使用,所以在union中不能包含虚函数

三六、匿名union是一个未命名的union,并且在右花括号和分号之间没有任何声明。对于匿名union,也直接访问它的成员。匿名union不能包含受保护成员或私有成员,也不能定义成员函数

三七、局部类不允许声明静态数据成员

三八、局部类只能访问外层作用域定义的类型名、静态变量以及枚举成员。如果局部类定义在某个函数内部,则该函数的普通局部变量不能被该局部类使用

三九、可以在局部类的内部再嵌套一个类

四十、所谓不可移植的特性是指因机器而异的特性,当将含有不可移植特性的程序从一台机器转移到另一个台机器上是,通常需要重新编写该程序

四一、位域的类型必须是整型或枚举类型。通常使用无符号类型保持一个位域

四二、取地址运算符(&)不能作用与位域,因此任何指针都无法指向类的位域

class Base
{
	
};

class Derived : public Base
{

};

class Screen
{
public:
	typedef string::size_type pos;
	char get_cursor() const 
	{
		return contents[cursor];
	}
	char get() const;
	char get(pos ht, pos wd) const;
	
    //char (Screen::* pmf) (Screen::pos, Screen::pos) const;

	// Action是一种可以指向Screen成员函数的指针,它接受2个pos实参,返回一个char
	//using Action =	char (Screen::*) (Screen::pos, Screen::pos) const;
    //Action pmf = &Screen::get;

	//Screen& action(Screen&, Action = &Screen::get);

	Screen& home();
	Screen& forward();
	Screen& back();
	Screen& up();
	Screen& down();
	//Action是一个指针,可以用任意一个光标函数对其赋值
	using Action = Screen& (Screen::*)();
	enum Directions {HOME, FORWARD, BACK, UP, DOWN};
	Screen& move(Directions);


	// 返回contents成员的指针
	static const string Screen::* data()
	{
		return &Screen::contents;
	}

private:
	string contents;
	pos cursor;
	pos height, width;
	static Action Menu[]; // 函数表
};

/*Screen& Screen::move(Directions cm)
{
	return (this->*Menu[cm])();
}*/

/*Screen::Action Screen::Menu[] = {
	&Screen::home,
	& Screen::forward,
	& Screen::back,
	& Screen::up,
	& Screen::down,
};*/

union Token
{
	char cval;
	int ival;
	double dval;
};

class AuthToken
{
public:
	AuthToken() : tok(INT), ival(0) {}
	AuthToken(const AuthToken& t) : tok(t.tok) { copyUnion(t); }
	AuthToken& operator=(const AuthToken&);
	// 如果union含有一个string成员,则必须销毁
	~AuthToken() { if (tok == STR) { sval.~basic_string(); } }
	AuthToken& operator=(const string&);
	AuthToken& operator=(char);
	AuthToken& operator=(int);
	AuthToken& operator=(double);


private:
	//enum etok { INT, CHAR, DBL, STR };
	//etok tok;
   enum { INT, CHAR, DBL, STR } tok; // 判别式, 类型与变量同时定义
	union {
		char cval;
		int ival;
		double dval;
		string sval;
	};
	void copyUnion(const AuthToken&);
};

AuthToken& AuthToken::operator=(int i)
{
	if (tok == STR)
	{
		sval.~basic_string();
	}
	ival = i;
	tok = INT;
	return *this;
}

AuthToken& AuthToken::operator=(char c)
{
	if (tok == STR)
	{
		sval.~basic_string();
	}
	cval = c;
	tok = CHAR;
	return *this;
}

AuthToken& AuthToken::operator=(double d)
{
	if (tok == STR)
	{
		sval.~basic_string();
	}
	dval = d;
	tok = DBL;
	return *this;
}

AuthToken& AuthToken::operator=(const string& s)
{
	if (tok == STR)
	{
		sval = s;
	}
	else {
		new (&sval) string(s);
	}
	tok = DBL;
	return *this;
}


AuthToken& AuthToken::operator=(const AuthToken& t)
{
	if (tok == STR && t.tok != STR) 
	{
		sval.~basic_string();
	}
	if (tok == STR && t.tok == STR)
	{
		sval = t.cval;
	}
	else {
		copyUnion(t);
	}
	tok = t.tok;
	return *this;
}

void AuthToken::copyUnion(const AuthToken& t)
{
	switch (t.tok) 
	{
	case AuthToken::INT: 
		ival = t.ival;
		break;
	case AuthToken::CHAR:
		cval = t.cval;
		break;
	case AuthToken::DBL:
		dval = t.dval;
		break;
	case AuthToken::STR:
		new (&sval) string(t.sval);
		break;
	}

}

void foo(int val)
{
	static int si;
	enum Loc { a = 1024, b };
	//局部类
	// 普通局部变量不能被局部类使用
	struct Bar
	{
		Loc locVal;
		int  barVal;

		void fooBar(Loc l = a)
		{
			//barVal = val; // 错误val是foo的局部变量
			barVal = si; // 正确,使用一个静态局部变量
			locVal = b;// 正确,使用枚举成员
		}
	};
}

typedef unsigned int Bit;
class File
{
	Bit mode : 2;// mode占2位
	Bit modified : 1;
	Bit prot_wener : 3;
	Bit prot_group : 3;
	Bit prot_world : 3;

public:
	enum modes {
		READ = 01, 
		WRITE = 02,
		EXECUTE = 03
	};
	File& open(modes);
	void close();
	void write();
	void isRead() const;
	void setWrite();
};
void File::write()
{
	modified = 1;
}
File& File::open(File::modes m)
{
	// 通常使用内置的位运算符操作位域
	mode != READ;
	if (m & WRITE)
	{

	}
	return *this;
}

int main()
{
	int arr[10];
	Derived d;
	Base* p = &d;

	cout << typeid(43).name() << endl;
	cout << typeid(arr).name() << endl;
	cout << typeid(string).name() << endl;
	cout << typeid(d).name() << endl;
	cout << typeid(p).name() << endl;
	cout << typeid(*p).name() << endl;

	// 在不限定作用域的枚举类型中,枚举成员的作用域与枚举类型本身的作用域相同
	enum color {red, yellow, green};
	//enum stoplight {red, yellow, green}; // 错误,重复定义了枚举成员
	enum class peppers {red, yellow, green};
	color eyes = green;
	//peppers p = green; // 错误,枚举成员不再有效作用域中
	peppers pes = peppers::green;

	int i = color::red;
	//int j = peppers::red;// 限定作用域的枚举类型不会进行隐式转换

	enum intValues : unsigned long long {
		charTyp = 255,
		shortTyp = 65535,
		intTyp = 65535
	};

	Screen myScreen, * pScreen = &myScreen;
	const string Screen::* pdata = Screen::data(); // 数据成员指针
	auto s = myScreen.*pdata; // .*解引用pdata以获得myScreen对象的成员
	auto s1 = pScreen->*pdata;// ->*解引用pdata以获得pScreen所指对象的成员
	//myScreen.move(Screen::HOME);
	
	//auto fp = &string::empty; // fp指向string的empty函数
	//vector<string> svec = { "how", "now", "the", "word" };
	vector<string> svec{ "how", "now", "the", "word" };
	//find_if(svec.begin(), svec.end(), fp); // 错误,必须使用.*或->*调用成员指针
	function<bool (const string&)> fcn = &string::empty;
	find_if(svec.begin(), svec.end(), fcn);
	// 与function不同的是,mem_fn可以根据成员指针的类型推断可调用对象的类型
	find_if(svec.begin(), svec.end(), mem_fn(&string::empty));
	// 可以使用bind从成员函数生成一个可调用对象
	find_if(svec.begin(), svec.end(), bind(&string::empty, placeholders::_1));

	Token firstToken = { 'a' }; // 初始化cval成员
	Token lastToken; // 未初始化
	Token* ptoken = new Token; // 指向一个未初始化的Token对象的指针
	lastToken.cval = 'z';
	ptoken->ival = 32;

	union {
		char cval2;
		int ival2;
		double dval2;
	};
	//匿名union可以直接访问它的成员
	ival2 = 32;


	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值