C++ Primer第五版_第十八章习题答案(21~30)

news/2024/10/18 9:19:57/

文章目录

      • 练习18.21
      • 练习18.22
      • 练习18.23
      • 练习18.24
      • 练习18.25
      • 练习18.26
      • 练习18.27
      • 练习18.28
      • 练习18.29
      • 练习18.30

练习18.21

解释下列声明的含义,在它们当作存在错误吗?如果有,请指出来并说明错误的原因。

(a) class CADVehicle : public CAD, Vehicle { ... };
(b) class DbiList : public List, public List { ... };
(c) class iostream : public istream, public ostream { ... };

(a)CADVehicle公开继承了CAD,私有继承了Vehicle;
(b)重复继承;
(c)iostream公开继承了istream和ostream。

练习18.22

已知存在如下所示的类的继承体系,其中每个类都定义了一个默认构造函数:

class A { ... };
class B : public A { ... };
class C : public B { ... };
class X { ... };
class Y { ... };
class Z : public X, public Y { ... };
class MI : public C, public Z { ... };

对于下面的定义来说,构造函数的执行顺序是怎样的?

MI mi;

A->B->C->X->Y->Z->MI。

练习18.23

使用练习18.22的继承体系以及下面定义的类 D,同时假定每个类都定义了默认构造函数,请问下面的哪些类型转换是不被允许的?

class D : public X, public C { ... };
p *pd = new D;
(a) X *px = pd;
(b) A *pa = pd;
(c) B *pb = pd;
(d) C *pc = pd;

(a)允许;
(b)允许;
(c)允许;
(d)允许。

练习18.24

在第714页,我们使用一个指向 Panda 对象的 Bear 指针进行了一系列调用,假设我们使用的是一个指向 Panda 对象的 ZooAnimal 指针将会发生什么情况,请对这些调用语句逐一进行说明。

pe->print() 正确;
pe->highlight() 错误;
pe->toes() 错误;
pe->duddle() 错误;
delete pe 正确。

练习18.25

假设我们有两个基类 Base1 和 Base2,它们各自定义了一个名为 print 的虚成员和一个虚析构函数。从这两个基类中文名派生出下面的类,它们都重新定义了 print 函数:

class D1 : public Base1 { /* ... */};
class D2 : public Base2 { /* ... */};
class MI : public D1, public D2 { /* ... */};

通过下面的指针,指出在每个调用中分别使用了哪个函数:

Base1 *pb1 = new MI;
Base2 *pb2 = new MI;
D1 *pd1 = new MI;
D2 *pd2 = new MI;
(a) pb1->print();
(b) pd1->print();
(c) pd2->print();
(d) delete pb2;
(e) delete pd1;
(f) delete pd2;
struct Base1 {void print(int) const;
protected:int ival;double dval;char cval;
private:int *id;
};
struct Base2 {void print(double) const;
protected:double fval;
private:double dval;
};
struct Derived : public Base1 {void print(std::string) const;
protected:std::string sval;double dval;
};
struct MI : public Derived, public Base2 {void print(std::vector<double>);
protected:int *ival;std::vector<double> dvec;
};

(a)MI::print();
(b)MI::print();
(c)MI::print();
(d)MI析构函数(会依次调用基类析构函数);
(e)MI析构函数(会依次调用基类析构函数);
(f)MI析构函数(会依次调用基类析构函数)。

练习18.26

已知如上所示的继承体系,下面对print的调用为什么是错误的?适当修改MI,令其对print的调用可以编译通过并正确执行。

MI mi;
mi.print(42);

没有匹配的print调用,当注释void print(std;:vector)时又会出现二义性;故为该函数定义一个新版本。

#include <iostream>
#include <vector>
struct Base1{void print(int) const{std::cout<<"Base1 Print Used"<<std::endl;};
protected:int ival;double dval;char cval;
private:int *id;
};
struct Base2 {void print(double) const;
protected:double fval;
private:double dval;
};struct Derived : public Base1 {
void print(std::string) const;
protected:std::string sval;double dval;
};struct MI : public Derived, public Base2{void print(std::vector<double>){};
void print(int x){Base1::print(x);
}
protected:int *ival;std::vector<double> dvec;
};using namespace std;int main()
{MI mi;mi.print(42);return 0;
}

练习18.27

已知如上所示的继承体系,同时假定为MI添加了一个名为foo的函数:

int ival;
double dval;
void MI::foo(double cval)
{int dval;//练习中的问题发生在此处
}
(a) 列出在MI::foo中可见的所有名字。
(b) 是否存在某个可见的名字是继承自多个基类的?
(c) 将Base1的dval成员与Derived 的dval 成员求和后赋给dval的局部实例。
(d) 将MI::dvec的最后一个元素的值赋给Base2::fval。
(e) 将从Base1继承的cval赋给从Derived继承的sval的第一个字符。

(a)Base1中,ival、dval、cval、print;
Base2中,fval、print;
Derived中,sval、dval、print;
MI中,ival、dvec、print、foo。
(b)存在,ival、dval、print。
(c)(d)(e)如下所示。

#include <iostream>
#include <vector>
struct Base1{void print(int) const{std::cout<<"Base1 Print Used"<<std::endl;};
protected:int ival;double dval;char cval = 'b';
private:int *id;
};
struct Base2 {void print(double) const;
protected:double fval;
private:double dval;
};struct Derived : public Base1 {
void print(std::string) const;
protected:std::string sval = "aaa";double dval;
};struct MI : public Derived, public Base2{void print(std::vector<double>){};
void print(int x){Base1::print(x);
}
void foo(double);protected:int *ival;std::vector<double> dvec = {1.0, 2.0, 3.0};
};int iva;
double dval;
void MI::foo(double cval)
{int dval;dval = Base1::dval + Derived::dval;Base2::fval = dvec.back();sval.at(0) = Base1::cval;
}int main()
{MI mi;mi.print(42);return 0;
}

练习18.28

已知存在如下的继承体系,在 VMI 类的内部哪些继承而来的成员无须前缀限定符就能直接访问?哪些必须有限定符才能访问?说明你的原因。

struct Base {void bar(int);
protected:int ival;
};
struct Derived1 : virtual public Base {void bar(char);void foo(char);
protected:char cval;
};
struct Derived2 : virtual public Base {void foo(int);
protected:int ival;char cval;
};
class VMI : public Derived1, public Derived2 { };

无需限定符的成员:
Derived1::bar(bar不仅是Base的成员,也是Derived1的成员,派生类的bar比共享虚机类的bar优先级更高);
Derived2::ival(派生类Derived2的ival比共享虚机类的ival优先级更高);
需要限定符的成员:
foo(Derived1和Derived2都存在该成员);
cval(Derived1和Derived2都存在该成员);
其他需要限定符的原因为会被覆盖。

练习18.29

已知有如下所示的类继承关系:

class Class { ... };
class Base : public Class { ... };
class D1 : virtual public Base { ... };
class D2 : virtual public Base { ... };
class MI : public D1, public D2 { ... };
class Final : public MI, public Class { ... };
(a) 当作用于一个Final对象时,构造函数和析构函数的执行次序分别是什么?
(b) 在一个Final对象中有几个Base部分?几个Class部分?
(c) 下面的哪些赋值运算符将造成编译错误?
Base *pb; Class *pc; MI *pmi; D2 *pd2;
(a) pb = new Class;
(b) pc = new Final;
(c) pmi = pb;
(d) pd2 = pmi;

(a)构造函数执行次序Class、Base、D1、D2、MI、Class、Final,析构函数执行次数与上述相反;
(b)一个Base两个Class;
(c)(a)编译错误,(b)编译错误,(c)编译错误,(d)正确。

练习18.30

在Base中定义一个默认构造函数、一个拷贝构造函数和一个接受int形参的构造函数。在每个派生类中分别定义这三种构造函数,每个构造函数应该使用它的形参初始化其Base部分。

#include <iostream>using namespace std;class Class {
};class Base : public Class {
public:// Base() = default;Base() { cout << "Base()" << endl; }Base(int) { cout << "Base(int)" << endl; }Base(const Base &b) {}
};class D1 : virtual public Base {
public:D1() = default;D1(int i) : Base(i) { cout << "D1(int)" << endl; }D1(const D1 &d){}
};class D2 : virtual public Base {
public:D2() = default;D2(int i) : Base(i) { cout << "D2(int)" << endl; }D2(const D2 &d) {}
};class MI : public D1, public D2 {
public:MI() = default;MI(int i) : D1(i), D2(i) { cout << "MI(int)" << endl; }MI(const MI &m) {}
};class Final : public MI, public Class {
public:Final() = default;// Final(int i) : MI(i) { cout << "Final(int)" << endl; }Final(int i) : MI(i), Base(i) { cout << "Final(int)" << endl; }Final(const Final &f) {}
};int main(int argc, char const *argv[])
{Final f(1);return 0;
}

http://www.ppmy.cn/news/103966.html

相关文章

多线程环境中的共享变量怎么保护起来的(volatile关键字与互斥锁)

文章目录 一、volatile关键字与互斥锁介绍&#xff08;1&#xff09;volatile关键字&#xff08;2&#xff09;互斥锁 二、volatile关键字与互斥锁的作用&#xff08;1&#xff09;第一个代码实例&#xff08;2&#xff09;第二个代码实例&#xff08;3&#xff09;第三个代码实…

TDengine 数据库SQL操作 | 建库、建表、数据读写

一、前文 TDengine 入门教程——导读 二、库操作 2.1 创建库 CREATE DATABASE test; BUFFER: 一个 VNODE 写入内存池大小&#xff0c;单位为 MB&#xff0c;默认为 96&#xff0c;最小为 3&#xff0c;最大为 16384。CACHEMODEL&#xff1a;表示是否在内存中缓存子表的最近数据…

【CTF】2023Ciscn WEB方向题解

前言 太菜了太菜了&#xff0c;太久没打比赛啥也不会做&#xff0c;部分题目可去NSSCTF进行复现:NSSCTF 比赛体验一般&#xff0c;一黑灯基本上题都烂掉 unzip 这道题估计大家都会&#xff0c;算是一道原题了 参考:https://xz.aliyun.com/t/10533 由于环境没了&#xff0c;靠…

javascript获取对象的键名列表、键值列表

Object.keys&#xff1a;获取对象的键名列表 Object.values&#xff1a;获取对象的键值列表 <script>var obj {name: 1,age: 2,order: 3}const klist Object.keys(obj)const vals Object.values(obj)console.log(obj, obj)console.log(键名列表, klist)console.log(键…

三十五、数学知识——快速幂(反复平方法 + 快速幂求逆元)

快速幂算法主要内容 一、基本原理1、概念 暴力求解2、核心原理——反复平方法3、快速幂求逆元 二、Java、C语言模板实现三、例题题解 一、基本原理 1、概念 暴力求解 问题目标&#xff1a; 快速求出 a^k mod p 的结果&#xff0c;时间复杂度为 O(logk)&#xff0c;其中 a,p…

【P43】JMeter 吞吐量控制器(Throughput Controller)

文章目录 一、吞吐量控制器&#xff08;Throughput Controller&#xff09;参数说明二、测试计划设计2.1、Total Executions2.2、Percent Executions2.3、Per User 一、吞吐量控制器&#xff08;Throughput Controller&#xff09;参数说明 允许用户控制后代元素的执行的次数。…

干货 | 出国留学申请必备的6种材料,速来!!!

Hello,大家好&#xff01; 这里是壹脑云科研圈&#xff0c;我是喵君姐姐~ 我们又见面啦~你还好吗&#xff1f; 这是喵君姐姐的第n篇诚意推送~ 01 为什么要留学&#xff1f; 想去看外面的世界&#xff1f;想要打破科研的壁垒&#xff1f;想去更好的平台提升自己&#xff1f…

WMS:系统窗口添加过程

WMS:系统窗口添加过程 1、经常使用的两大类窗口2、系统窗口StatusBar2.1 StatusBarWindowView添加流程2.2 简要时序图 android12-release 1、经常使用的两大类窗口 Android中的“窗口”类型有很多&#xff0c;经常使用的“窗口”大致分为两大类&#xff1a;一是&#xff0c;由系…