您的位置:首页 > 编程语言 > C语言/C++

C++Primer第五版 第十九章习题答案(1~10)

2017-03-23 09:26 405 查看
C++特殊的工具和技术
1:知识点1:new和delete运算符的实现细节:

new的操作过程:第一步、new表达式调用operator new(或者 operator new[])的标准库函数,该函数分配一块足够大的、原始的、未命名的内存空间以便存储特定类型的对象(或数组)。第二步、编译器运行相应的构造函数以构造这些对象,并为其传入初始值。第三步、对象分配了空间并构造完成,返回一个指向该对象的指针

delete的操作过程:第一步:对指针所指对象的数组指针所指数组执行相应的析构函数。第二步:编译器调用operator delete(或者operator
delete[])的标准库函数释放内存空间

知识点2:在自定义这两个标准库函数的时候,一定要弄对,因为这对计算机来说至关重要!

知识点3:重载new和delete,其实就是重载标准库的相关的两个operator函数

知识点4:实现的过程:若分配(释放)的对象是类类型,则编译器首先在类及其基类的作用域中查找,若该类中含有operator new成员或者operator delete成员,则相应表达式将调用这些成员,否则,编译器将在全局作用域查找匹配函数,若找到用户自定义版本,则执行,找不到,会使用标准库版本

知识点5:我们为一个对象分配空间时使用operator new,为一个数组分配空间时使用operator new[]

知识点6:C++从C语言中继承了malloc和free函数,头文件为cstdlib,malloc接受一个表示待分配字节数的size_t,返回指向该内存空间的指针或者返回0表示分配失败。free()函数接受一个void *,它是malloc返回指针的副本,free将相关内存返回给系统,free(0)无意义。所以operator
new可以用malloc来实现

#include <iostream>
#include <cstdlib>

void *operator new(std::size_t n){
std::cout << "new(size_t)"<<endl;
if (void *mem = malloc(n))
return mem;
else
throw std::bad_alloc();
}
void operator delete(void *mem) noexcept{
std::cout << "delete(void*)<<endl";
free(mem);
}
int main()
{
using namespace std;
int *a = new int(486);
cout << a << " " << *a << endl;
delete a;
system("pause");
return 0;
}


2:见上题

3:知识点1:operator new和operator delete和alloctor类的allocate和deallocate很像,都是负责分配和释放内存的函数,但是对于operator new分配的内存空间我们无法使用construct函数构造对象,我们应该使用new的定位new形式构造对象

知识点2:当只传入一个指针类型的实参时,定位new表达式构造对象但是不分配内存,这个指针没有要求,甚至可能是一个不是一个指向动态内存的指针

知识点3:调用析构函数会销毁对象,但是不会释放内存

知识点4:运行时类型识别(RTTI),typeid:用于返回表达式的类型,dynamic_cast:用于将基类的指针或引用转换成派生类的指针或引用,当我们将这两个运算符用于某种类型的引用或指针时,并且该类型含有虚函数,运算符将会使用指针或引用所绑定对象的动态类型

知识点5:RTTI使用情况:使用基类的指针或引用调用派生类的操作并且该操作不是虚函数,一般来说,我们应该尽量将其定义为虚函数(最好是定义为虚函数),编译器会根据对象的动态类型自动选择正确版本的函数

知识点6:三种形式:dynamic_cast<type *> (e)、dynamic_cast<type &> (e)、dynamic_cast<type
&&> (e)

type的类型必须含有虚函数,e分别为指针、左值、除了左值以外的类型,e需要满足的条件:目标type的共有派生类、目标type的共有基类或者就是目标type类型,转换失败时,指针类型返回0,引用类型转换失败抛出bad_cast异常,头文件为typeinfo

知识点7:可以对空指针进行dynamic_cast,结果是所需的空指针,在条件部分执行dynamic_cast可以确保类型转换和检查结果在同一条表达式中完成!

这里基类的指针或引用转化称为派生类的指针或者引用,需要注意的是该基类的指针需要指向的是派生类的对象才可以,否则指向基类对象的基类指针或引用是不可能转化为派生类的指针或引用的

/***************************************************************************
*  @file       main.cpp
*  @author     MISAYAONE
*  @date       21  March 2017
*  @remark     21  March 2017
***************************************************************************/

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <typeinfo>
using namespace std;

class A
{
public:
A()
{
cout<<"A()"<<endl;
}
virtual ~A()
{
cout<<"~A()"<<endl;
}
};

class B:public A
{
public:
B()
{
cout<<"B()"<<endl;
}
virtual ~B()
{
cout<<"~B()"<<endl;
}
};
class C:public B
{
public:
C()
{
cout<<"C()"<<endl;
}
virtual ~C()
{
cout<<"~C()"<<endl;
}
};
class D:public B,public A
{
public:
D()
{
cout<<"D()"<<endl;
}
virtual ~D()
{
cout<<"~D()"<<endl;
}
};
int main(int argc,char** argv)
{
A *pa = new C;
if (B *pb = dynamic_cast<B*>(pa))
{
cout<<"True"<<endl;
}
else
{
cout<<"False"<<endl;
}//因为指针类型的转换失败返回为0可以使用条件中赋值判断

try
{
C &cp = dynamic_cast<C&>(*pa);//正确,*pa的类型是C
cout << "cp" << endl;
}
catch (std::bad_cast e)
{
cout << e.what() << endl;
}//引用类型失败返回的是bad_cast

B *pbb = new B;
if (C *pc = dynamic_cast<C*>(pbb))
{
cout<<"True"<<endl;
}
else
{
cout<<"False"<<endl;
}

A *paa = new D;
if (B *pc = dynamic_cast<B*>(paa))
{
cout<<"True"<<endl;
}
else
{
cout<<"False"<<endl;
}

cin.get();
return 0;
}


5:前面有说到并非任何时候都能有虚函数,假设有一个基类的指针指向其派生类,派生类中有一个成员基类中没有,这时候想通过这个基类的指针来调用这个成员就是不可以的,此时可以用dynamic_cast

6、7、8:知识点1:typeid(e),其中e可以是任何类型或表达式的名字,若为表达式,返回的是引用所引对象的类型,若作用域数组名,返回的是数组类型,若作用于指针,返回的是该指针的静态编译的类型

//19.6
Query_base *pb1 = new AndQuery(Query("value1"), Query("value2"));
Query_base *pb2 = new OrQuery(Query("value1"), Query("value2"));
if (AndQuery *pa1 = dynamic_cast<AndQuery*>(pb1)) {
cout << "成功" << endl;
}
else {
cout << "失败" << endl;
}
if (AndQuery *pa2 = dynamic_cast<AndQuery*>(pb2)) {
cout << "成功" << endl;
}
else {
cout << "失败" << endl;
}
//19.7
try {
AndQuery &ra1 = dynamic_cast<AndQuery&>(*pb1);
cout << "成功" << endl;
}
catch (bad_cast e) {
cout << e.what() << endl;
}
try {
AndQuery &ra2 = dynamic_cast<AndQuery&>(*pb2);
cout << "成功" << endl;
}
catch (bad_cast e) {
cout << e.what() << endl;
}
//19.8
if (typeid(*pb1) == typeid(*pb2))
cout << "pd1与pd2指向的对象类型相同" << endl;
else
cout << "pd1与pd2的动态类型不相同" << endl;
if (typeid(*pb1) == typeid(AndQuery))
cout << "pd1的动态类型是AndQuery" << endl;
else
cout << "pd1的动态类型并非是AndQuery" << endl;
if (typeid(*pb2) == typeid(AndQuery))
cout << "pd2的动态类型是AndQuery" << endl;
else
cout << "pd2的动态类型并非是AndQuery" << endl;


9:知识点1:回头看下第五题,派生类中的 == 相等运算符是需要考虑到派生类自身成员的,但是使用虚函数的方式,形参列表必须一致,这时候就需要运行时识别了

知识点2:type_info的name()成员返回一个C风格的字符串,表示对象的类型名字,由编译器决定

自己试试看吧

/***************************************************************************
*  @file       main.cpp
*  @author     MISAYAONE
*  @date       21  March 2017
*  @remark     21  March 2017
***************************************************************************/

#include <iostream>
#include <vector>
#include <list>
#include <string>
#include <typeinfo>
using namespace std;

int main(int argc,char** argv)
{
int arr[41];
double i = 6.23;
vector<int> vec1;
int *p = arr;
cout<<typeid(arr).name()<<endl;
cout<<typeid(i).name()<<endl;
cout<<typeid(vec1).name()<<endl;
cout<<typeid(p).name()<<endl;

cin.get();
return 0;
}


10:

a、class A* 指针类型

b、class A* 引用类型

c、class B 引用指向的类型
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息