栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > C/C++/C#

19 C++ 特殊工具与技术

C/C++/C# 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

19 C++ 特殊工具与技术

系列文章目录

文章目录
  • 系列文章目录
  • 前言
  • 控制内存分配
    • 定位new表达式
  • 运行时类型时别
    • dynamic_cast运算符
    • typeid运算符
    • 使用RTTI
    • type_info类
  • 枚举类型
  • 类成员指针
    • 数据成员指针
    • 成员函数指针
    • 将成员函数用作可调用对象
  • 嵌套类
  • union:一种节省空间的类
  • 局部类
  • 固有的不可移植的特性
    • 位域
    • volatile限定符
    • 链接指示:extern “C”
  • 总结


前言

该章节为扩展内容


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

operator new接口和operator delete接口


malloc 函数与 free函数

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(e)
dynamic_cast(e)
dynamic_cast(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 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::shared_ptr>);
};

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

定义嵌套类的成员

TextQuery::QueryResult::QueryResult(string s,
									shared_ptr> p,
									shared_ptr> 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> nodata(new set);
	//使用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;
转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/935897.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号