//new表达式
string *sp = new string("a value"); //分配并初始化一个string对象
string *arr = new string[10]; //分配10个默认初始化的string对象
new表达式调用一个名为operator new(或者operator new[])的标准库函数。分配一块足够大的、原始的、未命名的内存空间。
编译器运行相应的构造函数以构造这些对象,并为其传入初始值。
对象被分配了空间并构造完成,返回一个指向该对象的指针。
2. delete表达式的工作机理
delete sp; //销毁*sp,然后释放sp指向的内存空间
delete[] arr; //销毁数组中的元素,然后释放对应的内存空间
对指针所指的对象执行对应的析构函数。
编译器调用名为operator delete(或者operator delete[])的标准库函数释放内存空间。
3. 可以使用作用域运算符令new或delete忽略定义在类中的函数,直接执行全局作用域中的版本,如::new。
4. 提供新的operator new函数和operator delete函数的目的在于改变内存分配的方式,不管怎样,都不能改变new运算符和delete运算符的基本含义。
#include // std::cout
struct MyClass {
MyClass() { std::cout << "MyClass constructed\n"; }
~MyClass() { std::cout << "MyClass destroyed\n"; }
//operator new函数和operator delete函数,可以定义为全局作用域,也可以定义为成员函数。
void* operator new(size_t t) {
puts("override version:normal...");
void* m = malloc(t);
if (m) return m;
else throw std::bad_alloc();
}
void* operator new(size_t t, std::nothrow_t obj) noexcept {
puts("override version:nothrow");
//return operator new(t);
void* m = malloc(t);
return m;
}
//如果刚刚失败的new是nothrow版本,那么要调用的delete操作符将是nothrow版本,否则将是正常版本。这个过程是自动的。
void operator delete(void* p) noexcept {
puts("deleting normal...");
free(p);
}
void operator delete(void* p, std::nothrow_t obj) noexcept {
puts("deleting nothrow...");
free(p);
}
};
int main() {
MyClass* pt = new (std::nothrow) MyClass;
delete pt;
//MyClass::operator delete(pt,std::nothrow);
std::cout << std::endl;
MyClass* pt2 = new MyClass;
delete pt2;
}
#include
class Foo {
public:
Foo(int val = 0){_val = val;}
void writeFoo() {
std::cout << "_val:" << _val << " address:" << this;
std::cout << std::endl;
}
~Foo() = default;
private:
int _val;
};
int main(int argc, char* argv[]) {
//创建char数组,大小为3个Foo
char* buf = new char[sizeof(Foo) * 3];
//实例化Foo对象,并将其放置到buf中第1个Foo“位置”处
Foo* pb = new (buf) Foo(0);
//实例化Foo对象,并将其放置到buf中第3个Foo“位置”处
Foo* pb1= new (buf + sizeof(Foo) * 2) Foo(1);
//实例化Foo对象,并将其放置到buf中第2个Foo“位置”处
Foo* pb2= new (buf + sizeof(Foo)) Foo(2);
pb->~Foo();
//delete pb;
pb->writeFoo();
pb1->writeFoo();
pb2->writeFoo();
}
struct Base {
virtual ~Base() {};
};
struct Derived : public Base { };
int main() {
Base* bp;
bp = new Derived; // bp actually points to a Derived object
//bp = new Base; // bp points to a Base object
if (Derived * dp = dynamic_cast<Derived*>(bp)) {
puts(" use the Derived object to which dp points");
}
else { // bp points at a Base object
puts(" use the Base object to which bp points");
}
}
Derived* dp = new Derived;
Base* bp = dp; //两个指针都指向Derived对象
//在运行时比较两个对象的类型
if (typeid(*bp) == typeid(*dp))
cout << "指向的是同一种类型" << endl;
//检查运行时类型是否是某种给定的类型
if (typeid(*bp) == typeid(Derived))
cout << "bp实际指向Derived对象" << endl;
//下面的检查永远是失败的:bp的类型是指向Base的指针
if (typeid(bp) == typeid(Derived)) {
}
class Base {
friend bool operator==(const Base&, const Base&);
public:
//Base的接口成员
protected:
//如果定义一个虚函数equal,则该函数的形参必须是基类的引用。此时,equal函数将只能使用基类的成员,而不能比较派生类独有的成员
virtual bool equal(const Base&) const;
//Base的数据成员和其他用于实现的成员
};
class Derived :public Base {
public:
//Derived的其他成员
protected:
//虚函数的基类版本和派生类版本必须具有相同的形参类型。
bool equal(const Base&) const;
//Derived的数据成员和其他用于实现的成员
};
bool operator==(const Base& lhs, const Base& rhs) {
//如果typeid不同,返回false;否则虚调用equal
return typeid(lhs) == typeid(rhs) && lhs.equal(rhs);
}
bool Derived::equal(const Base& rhs) const {
//我们清楚这两个类型是相等的,所以转换过程不会抛出异常
auto r = dynamic_cast<const Derived&>(rhs);
//指向比较两个Derived对象的操作并返回结果
}
int main() {
int arr[10];
Derived d;
Base *p = &d;
cout << typeid(42).name() << ", " << std::endl
<< typeid(arr).name() << ", " << std::endl
<< typeid(std::string).name() << ", " << std::endl
<< typeid(p).name() << ", " << std::endl
<< typeid(*p).name() << endl;
return 0;
}
enum class open_modes { input, output, append };
enum color {red, yellow, green}; //不限定作用域的枚举类型
//未命名的、不限定作用域的枚举类型
enum { floatPrec = 6, doublePrec = 10, double_doublePrec = 10 };
enum color { red, yellow, green };
enum stoplight { red, yellow, green }; //错误:重复定义了枚举成员
enum class peppers { red, yellow, green }; //正确:枚举成员被隐藏了
color eyes = green; //正确:枚举类型的枚举成员位于有效的作用域中
peppers p = green; //错误:pepers的枚举成员不在有效的作用域中
//color::green在有效的作用域中,但是类型错误
color hair = color::red; //正确
peppers p2 = peppers::red; //正确:显式的使用pappers的red
enum class intTypes {
charTyp = 8, shortTyp = 16, intTyp = 16,
longTyp = 32, long_longTyp = 64
};
color red1 = 1; //错误:
int i = color::red; //正确:不限定作用域的枚举类型的枚举成员隐式地转换成int
int j = peppers::red; //错误:限定作用域的枚举类型不会隐式转换
enum intValues : unsigned long long {
charType = 255, shortTyp=65535, intTyp = 65535,
longTyp = 4294967295UL,
long_longTyp = 1844674407370951615ULL
};
enum Tokens { INLINE = 128, VIRTUAL = 129 };
void ff(Tokens);
void ff(int);
int main() {
Tokens curTok = INLINE;
ff(128); //精确匹配ff(int)
ff(INLINE); //精确匹配ff(Tokens)
ff(curTok); //精确匹配ff(Tokens)
return 0;
}
void newf(unsigned char);
void newf(int);
unsigned char uc = VIRTUAL;
//不管Tokens的潜在类型到底是什么,它的对象和枚举成员都提升成int
newf(VIRTUAL); //调用newf(int)
newf(uc); //调用newf(unsigned char)
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;
//一个指向Screen类的const string成员的指针
pdata = &Screen::contents; //初始化
//初始化后,该指针并没有指向任何对象
//auto pdata = &Screen::contenets;
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; }
//其他成员与之前的版本一致
};
//data()返回一个指向Screen类的contents成员的指针
const string Screen::*pdata = Screen::data();
//获得myScreen对象的contents成员
auto s = myScreen.*pdata;
//pmf是一个指针,它可以指向Screen的某个常量成员函数
auto pmf = &Screen::get_cursor;
char (Screen::*pmf2)(Screen::pos, Screen::pos) const;
pmf2 = &Screen::get;//&不能省
Screen myScreen, *pScreen = &myScreen;
//通过pScreen所指的对象调用pmf所指的函数
char c1 = (pScreen->*pmf)();
//通过myScreen对象将实参0,0传给含有两个形参的get函数
char c2 = (myScreen.*pmf2)(0,0);
//指向Screen成员函数的指针,接受两个pos实参,返回一个char
using Action = char(Screen::*)(Screen::pos, Screen::pos) const;
Action get = &Screen::get; //get指向Screen的get成员
//接受一个Screen的引用,和一个指向Screen成员函数的指针
Screen& action(Screen&, Action = &Screen::get);
Screen myScreen;
//等价调用
action(myScreen); //使用默认实参
action(myScreen, get); //使用我们之前定义的变量get
action(myScreen, &Screen::get); //显式传入地址
class Screen {
public:
//其他接口和实现成员与之前一致
using Action = Screen&(Screen::*)();
//光标移动函数
Screen& home() { cursor = 0; return *this; }
Screen& forward() { ++cursor; return *this; }
Screen& back() { --cursor; return *this; }
Screen& up() { cursor += height; return *this; }
Screen& down() {cursor -= height; return *this; }
enum Directions { HOME, FORWARD, BACK, UP, DOWN };
Screen& move(Directions);
private:
static Action Menu[]; // 函数表
};
Screen& Screen::move(Directions cm)
{
// run the element indexed by cm on this object
return (this->*Menu[cm])(); // Menu[cm] points to a member function
}
Screen::Action Screen::Menu[] = { &Screen::home,
&Screen::forward,
&Screen::back,
&Screen::up,
&Screen::down,
};
Screen myScreen;
myScreen.move(Screen::HOME); // invokes myScreen.home
myScreen.move(Screen::DOWN); // invokes myScreen.down
vector<string> svec;
auto fp = &string::empty; //fp指向string的empty函数
//错误,必须使用.*或->*调用成员指针
find_if(svec.begin(), svec.end(), fp);
//检查对当前元素的断言是否真
if(fp(*it)) //错误:要想通过成员指针调用函数,必须使用->*运算符
function<bool (const string&)> fcn = &string::empty;
find_if(svec.begin(), svec.end(), fcn);
//指向成员函数的对象将被传给隐式的this形参
//假设it是find_if内部的迭代器,则*it是给定范围的一个对象
if(fcn(*it))
//本质上function将函数调用转换成了如下形式:
if((*it).*p)()) //假设p是fcn内部的一个指向成员函数的指针
//mem_fn(&string::empty)生成一个可调用对象
find_if(svec.begin(), svc.end(), mem_fn(&string::empty));
//mem_fn生成的可调用对象含有一对重载的函数调用运算符
auto f = mem_fn(&string::empty); //f接受一个string或者一个string*
f(*svec.begin()); //正确:传入一个string对象,f使用.*调用empty
f(&svec[0]); //正确:传入一个string的指针,f使用->*调用emtpy
//选择范围中的每个string,并将其bind到empty的第一个隐式实参上
auto it = find_if(svec.begin(), svec.end(), bind(&string::empty,_1));
auto f = bind(&string::empty, _1);
f(*svec.begin()); //正确:实参是一个string,f使用.*调用empty
f(&svec[0]); //正确:实参是一个string的指针,f使用->*调用empty
class TextQuery {
public://嵌套的类就像是一个外层类的成员一样,受到访问限制符的影响
class QueryResult;
//...
};
class TextQuery::QueryResult {
friend std::ostream& print(std::ostream&, const QueryResult&);
public:
//无须定义QueryResult::line_no
//嵌套类使用外层类的成员时无需对该成员的名字进行限定
QueryResult(std::string, std::shared_ptr<std::set<line_no>>,
std::shared_ptr<st::vector<std::string>>);
//...
};
TextQuery::QueryResult::QueryResult(string s,
shared_ptr<set<line_no>> p,
shared_ptr<vector<string>> f):
sought(s),clines(p), file(f) { }
//假设QueryResult有一个静态成员,则该成员的定义形式如下:
int TextQuery::QueryResult::static_mem = 1024;
//返回类型必须指明QueryResult是一个嵌套类
TextQuery::QueryResult
TextQuery::query(const string &sought) const {
//如果没有找到sought,则返回set的指针
static shared_ptr<set<line_no>> nodata(new set<line_no>);
//使用find而非下标以避免向wm中添加单词
auto loc = wm.find(sought);
if(loc == wm.end())
return QueryResult(sought, nodata, file);
else
return QueryResult(sought, loc->second, file);
}
union Token {
//默认情况下成员是公有的
char cval;
int ival;
double dval;
};
Token first_token = {'a'}; //初始化union的第一个成员
Token last_token; //未初始化的Token对象
Token *pt = new Token; //指向一个未初始化的Token对象的指针
last_token.cavl = 'z';
pt->ival = 42;
union {
char cval;
int ival;
double dval;
}; //定义一个未命名的对象,我们可以直接访问它的成员
//在匿名union的定义所在的作用域,union的成员都可以直接访问
cval = 'c'; //为未命名的对象赋值
ival = 42; //该对象状态改变
class Token {
public:
// copy control needed because our class has a union with a string member
Token(): tok(INT), ival(0) { }
Token(const Token &t): tok(t.tok) { copyUnion(t); }
Token &operator=(const Token&);
// if the union holds a string, we must destroy it;
~Token() { if (tok == STR) sval.~string(); }
// assignment operators to set the differing members of the union
Token &operator=(const std::string&);
Token &operator=(char);
Token &operator=(int);
Token &operator=(double);
private:
enum {INT, CHAR, DBL, STR} tok; // 判别式:追踪union的状态
union { // anonymous union
char cval;
int ival;
double dval;
std::string sval;
}; // each Token object has an unnamed member of this unnamed union type
// 检查判别式,然后酌情拷贝union成员
void copyUnion(const Token&);
};
Token &Token::operator=(int i) {
if (tok == STR) sval.~string(); // if we have a string, free it
ival = i; // assign to the appropriate member
tok = INT; // update the discriminant
return *this;
}
// char,double的版本基本和上面一致…
Token &Token::operator=(const std::string &s) {
if (tok == STR) // if we already hold a string, just do an assignment
sval = s;
else
new(&sval) std::string(s); // otherwise construct a string
tok = STR; // update the discriminant
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;
// to copy a string, construct it using placement new;
case Token::STR: new(&sval) std::string(t.sval); break;
}
}
Token &Token::operator=(const Token &t) {
// if this object holds a string and t doesn't, we have to free the old string
if (tok == STR && t.tok != STR) sval.~string();
if (tok == STR && t.tok == STR)
sval = t.sval; // no need to construct a new string
else
copyUnion(t); // will construct a string if t.tok is STR
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 barVar;
void fooBar(Loc i = a) //正确:默认实参是Loc::a
{
barVal = val; //错误:val是foo的局部变量
barVal = ::val; //正确:使用一个全局对象
barVal = si; //正确:使用一个静态局部对象
locVal = b; //正确:使用一个枚举成员
}
};
//...
}
void foo()
{
class Bar {
public:
//...
class Nested; //声明Nested类
};
//定义Nested类
class Bar::Nested {
//...
};
}
typedef unsigned int Bit;
class File {
Bit mode: 2; // mode has 2 bits
Bit modified: 1; // modified has 1 bit
Bit prot_owner: 3; // prot_owner has 3 bits
Bit prot_group: 3; // prot_group has 3 bits
Bit prot_world: 3; // prot_world has 3 bits
public:
enum modes { READ = 01, WRITE = 02, EXECUTE = 03 };
File &open(modes);
void close();
void write();
bool isRead() const;
void setWrite();
void execute();
bool isExecute() const;
};
void File::write(){ modified = 1; // . . .}
void File::close(){if (modified) // . . . save contents; }
inline bool File::isRead() const { return mode & READ; }
inline void File::setWrite() { mode |= WRITE; }
File &File::open(File::modes m) {
mode |= READ; // set the READ bit by default
// other processing
if (m & WRITE) // if opening READ and WRITE
// processing to open the file in read/write mode
cout << "myFile.mode WRITE is set" << endl;
return *this;
}
int main() {
File myFile;
myFile.open(File::READ);
if (myFile.isRead())
cout << "reading" << endl;
return 0;
}
volatile int display_register; //该int值可能发生改变
volatile Task *curr_task; //curr_task指向一个volatile对象
volatile int iax[max_size]; //iax的每个元素都是volatile
volatile Screen bitmapBuf; //bitmapBufd的每个成员都是volatile
volatile int v; //v是一个volatile int
int *volatile vip; //vip是一个volatile指针,它指向int
volatile int * ivp; //vip是一个指针,指向volatile int
//vivp是一个volatile指针,它指向一个volatile int
volatile int *volatile vivp;
int *ip = &v; //错误:必须使用指向volatile的指针
ivp = &v; //正确:ivp是一个指向volatile的指针
vivp = &v; //正确:vivp是一个指向volatile的volatile指针
class Foo {
public:
Foo(const volatile Foo&); //从一个volatile对象进行拷贝
//将一个volatile对象赋值给一个非volatile对象
Foo& operator=(volatile const Foo&);
//将一个volatile对象赋值给一个volatile对象
Foo& operator=(volatile const Foo&) volatile;
//Foo类的剩余部分...
}
//可能出现在C++头文件中的链接指示
//单语句链接指示
extern "C" size_t strlen(const char *);
//复合语句链接指示
extern "C" {
int strcmp(const char*, const char*);
char *strcat(char*,const char*);
}
//复合语句链接指示
extern "C" {
#include //操作C风格字符串的C函数
//头文件中的所有普通函数声明都被认为是由链接指示的语言编写的
//链接指示可以嵌套
}
//f1是一个C函数,它的形参是一个指向C函数的指针
extern "C" void f1(void(*)(int));
//FC是一个指向C函数的指针
extern "C" typedef void FC(int);
//f2是一个C++函数,该函数的形参是执行C函数的指针
void f2(FC*);
//pf指向一个C函数,该函数接受一个int返回void
extern "C" void (*pf)(int);
void (*pf1)(int); //指向一个C++函数
extern "C" void (*pf2)(int); //指向一个C函数
pf1 = pf2; //错误:pf1和pf2的类型不同
//calc函数可以被C程序调用
extern "C" double calc(double dparm) {/*...*/}
//编译器将为该函数生成适合于指定语言的代码
//错误:两个extern"C"函数的名字相同
extern "C" void print(const char*);
extern "C" void print(int);
class SamllInt { /*...*/ };
class BigNum { /*...*/ };
//C函数可以在C或C++程序中调用
//C++函数重载了该函数,可以在C++程序中调用
extern "C" double calc(double);
extern SmallInt calc(const SmallInt&);
extern BigNum calc(const BigNum&);