19.1
#include <iostream> #include <cstdlib> using namespace std; void* operator new(size_t n) { if (void *p = malloc(n)) return p; else throw bad_alloc(); } void operator delete(void *p) noexcept { free(p); } int main() { int *ps = new int; delete ps; return 0; }
19.2
allocator类将使用我们自定义的版本替换标准库定义的版本,来获取/释放存储空间。
19.3
(a):失败,pa指向派生类C,而B是C的基类,故无法转换
(b):成功
(c):失败,同(a)
其他人的答案:
(a):正确,pa指向C构造的对象的A部分
(b):失败,pb指向的对象不包含C对象
(c):正确
19.4
A *pa = new C; //pa指向C,*pa的类型是C try { C &c = dynamic_cast<C&>(*pa); //使用C的成员 } catch(bad_cast) { //使用A的成员 }
19.5
使用dynamic_cast运算符代替虚函数:使用基类对象的指针或引用执行某个(不是虚函数)派生类操作时
19.6
Query_base *q = new AndQuery(Query("val1"), Query("val2")); AndQuery a(Query("ss1"), Query("ss2")); if (typeid(*q) == typeid(a)) cout << "success "; else cout << "failure ";
19.7
Query_base q; AndQuery a(Query("ss1"), Query("ss2")); try { AndQuery aa = dynamic_cast<AndQuery&>(q); cout << "success "; } catch (bad_cast) { cout << "failure "; }
19.8
Query_base *pb1 = new AndQuery(Query("value1"), Query("value2")); Query_base *pb2 = new OrQuery(Query("value1"), Query("value2")); if (typeid(*pb1) == typeid(*pb2)) cout << "pb1与pb2指向的对象类型相同" << endl; else cout << "pb1与pb2的动态类型不相同" << endl; if (typeid(*pb1) == typeid(AndQuery)) cout << "pb1的动态类型是AndQuery" << endl; else cout << "pb1的动态类型并非是AndQuery" << endl; if (typeid(*pb2) == typeid(AndQuery)) cout << "pb2的动态类型是AndQuery" << endl; else cout << "pb2的动态类型并非是AndQuery" << endl;
19.9
#include <iostream> #include <typeinfo> using namespace std; int main() { int i = 2, a[10] = {0}; double d = 0; string s; cout << typeid(i).name() << endl << typeid(a).name() << endl << typeid(d).name() << endl << typeid(s).name() << endl; return 0; }
19.10
(a):类型A*
(b):类型C*
(c):类型B
19.11
普通的数据指针:指向一个对象
指向数据成员的指针:指示的是类的成员(而非类的对象)
19.12
#include <iostream> #include <typeinfo> using namespace std; class Screen { public: typedef string::size_type pos; Screen(): cursor(0), height(0), width(0) {} char get_cursor() const { return contents[cursor]; } char get() const; char get(pos ht, pos wd) const; static pos Screen::* co() { return &Screen::cursor; } // pos Screen::*p = &Screen::cursor; private: string contents; pos cursor; pos height, width; }; int main() { Screen scr; auto p = scr.co(); auto ans = scr.*p; cout << ans << endl; return 0; }
19.13
类型:const string Sales_data::*
示例:const string Sales_data::*p = &Sales_data::bookNo;
19.14
第一个合法:pmf为指向Screen类成员函数get_cursor的指针
第二个不合法:get函数存在重载的问题,我们必须显式地声明函数类型以明确指出我们想要使用的是哪个函数
修正:
char (Screen::*pmf)(Screen::pos, Screen::pos) const; pmf = &Screen::get; //way2 using Action = char (Screen::*)(Screen::pos, Screen::pos) const; Action pmf = &Screen::get;
19.15
指向成员函数的指针:在成员函数和指向该成员的指针之间不存在自动转换规则
19.16
using Action = double (Sales_data::*)() const;
19.17
char get() const { return contents[cursor]; }//using Action_c_v = char (Screen::*)()const; char get_cursor() const { return contents[cursor]; }//同上 inline char get(pos ht, pos wd) const;//using Action_c_uu = char (Screen::*)(pos,pos)const; Screen &move(pos r, pos c);//using Action_Screen_uu = Screen &(Screen::*)(pos,pos);
19.18
int a = count_if(svec.begin(), svec.end(), bind(&string::empty, _1));
19.21
#include <iostream> using namespace std; class Token { public: Token(): tok(INT), ival(0) { } Token(const Token &t): tok(t.tok) { copyUnion(t); } Token &operator=(const Token&); ~Token() { if (tok == STR) sval.~string(); } Token &operator=(const string&); Token &operator=(char); Token &operator=(int); Token &operator=(double); private: enum {INT, CHAR, DBL, STR} tok; union { char cval; int ival; double dval; string sval; }; void copyUnion(const Token&); }; void Token::copyUnion(const Token &t) { switch (t.tok) { case INT: ival = t.ival; break; case CHAR: cval = t.cval; break; case DBL: dval = t.dval; case STR: new(&sval) string(t.sval); break; } } Token &Token::operator=(const Token &t) { if (tok == STR && t.tok != STR) sval.~string(); else if (tok == STR && t.tok == STR) sval = t.sval; else copyUnion(t); tok = t.tok; return *this; } Token &Token::operator=(int i) { if (tok == STR) sval.~string(); ival = i; tok = INT; return *this; } Token &Token::operator=(double d) { if (tok == STR) sval.~string(); dval = d; tok = DBL; return *this; } Token &Token::operator=(char c) { if (tok == STR) sval.~string(); cval = c; tok = CHAR; return *this; } Token &Token::operator=(const string &s) { if (tok == STR) sval = s; else new(&sval) string(s); tok = STR; return *this; }
19.22
class Token { public: //其他见上题 class Sales_data; };
19.23
Token(Token &&t): tok(std::move(t.tok)) { moveUnion(std::move(t)); } Token &operator=(Token &&t);
19.24
将一个Token对象赋给另一个Token对象:会运行拷贝赋值运算符,然后根据判别式的值来对相应的数据成员赋值。
类似的,将一个Token对象赋给它自己的过程和上面的类似。
19.25
Token &Token::operator=(int i) { if (tok == STR) sval.~string(); ival = i; tok = INT; return *this; } Token &Token::operator=(double d) { if (tok == STR) sval.~string(); dval = d; tok = DBL; return *this; } Token &Token::operator=(char c) { if (tok == STR) sval.~string(); cval = c; tok = CHAR; return *this; } Token &Token::operator=(const string &s) { if (tok == STR) sval = s; else new(&sval) string(s); tok = STR; return *this; }
补充:
Token &Token::operator=(const Token &t) { if (tok == STR && t.tok != STR) sval.~string(); else if (tok == STR && t.tok == STR) sval = t.sval; else copyUnion(t); //内含各种类型的赋值 tok = t.tok; return *this; } void Token::copyUnion(const Token &t) { switch (t.tok) { case INT: ival = t.ival; break; case CHAR: cval = t.cval; break; case DBL: dval = t.dval; case STR: new(&sval) string(t.sval); break; } }
19.26
错误,C语言不支持函数重载