系列文章目录
文章目录
前言
该章节为扩展内容
控制内存分配
// new expression
string *sp = new string("a value");
- 调用operator new函数分配内存空间
- 编译器运行相应构造函数进行初始化
- 返回指向该对象的指针
delete sp;
- 调用析构函数
- 编译器调用operator delete的标准库函数释放内存空间
operator new接口和operator delete接口
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;