习题选自:C Primer Plus(第六版) 内容仅供参考,如有错误,欢迎指正 ! 第十三章- 类继承学习笔记
复习题
1. 派生类从基类那里继承了什么?
派生类继承了基类的公有成员、基类的保护成员和基类的私有成员,但派生类不能直接访问从基类继承过来的私有成员。
2. 派生类不能从基类那里继承什么?
派生类不能继承构造函、析构函数、赋值运算符合友元。
3. 假设baseDMA::operator=()函数的返回类型为void,而不是baseDMA &,这将有什么后果?如果返回类型为baseDMA,而不是baseDMA &,又将有什么后果?
如果返回值为void
的,则baseDMA
对象仍可以使用单个赋值,但是不能使用连续赋值。即:
baseDMA magazine("Pandering to Glitz", 1);
baseDMA gift1, gift2, gift3;
gift1 = magazine; //ok
gitft2 = gift3 = gift1; //no 不可用
如果方法返回类型为baseDMA
,则该方法返回的是一个对象,不是引用,导致返回语句的时候需要复制对象,导致该方法执行速度会有所减慢。
4. 创建和删除派生类对象时,构造函数和析构函数调用的顺序是怎样的?
按照派生的顺序调用构造函数,最早的构造函数最先调用。调用析构函数的顺序正好相反。
5. 如果派生类没有添加任何数据成员,它是否需要构造函数?
需要,每个类都必须有自己的构造函数,如果派生类没有添加新成员,则构造函数可以为空,但必须存在。
6. 如果基类和派生类定义了同名的方法,当派生类对象调用该方法时,被调用的将是哪个方法?
调用派生类方法,它取代基类定义。仅当派生类没有重新定义方法或使用作用域解析运算符时,才会调用基类方法。
7. 在什么情况下,派生类应定义赋值运算符?
如果派生类构造函数使用new或者new[]运算符来初始化类的指针成员,则应定义一个赋值运算符。更普通的说,如果对于派生类成员来说,默认赋值不正确,则应定义赋值运算符。
8. 可以将派生类对象的地址赋给基类指针吗?可以将基类对象的地址赋给派生类指针吗?
可以将派生类对象的地址赋给基类指针。但只有通过显示类型转换,才可以将基类对象的地址赋给派生类指针(向下转换),而使用这样的指针不一定安全。
9. 可以将派生类对象赋给基类对象吗?可以将基类对象赋给派生类对象吗?
可以将派生类对象的地址赋值给基类对象,对于派生类中新增的数据成员都不会传递给基类对象,程序也将使用基类的赋值运算符。仅当派生类定义了转换运算符(即包含将基类引用作为唯一参数的构造函数)或使用基类为参数的赋值运算符时,相反的赋值才是可能的。
10. 假设定义了一个函数,它将基类对象的引用作为参数。为什么该函数也可以将派生类对象作为参数?
应为c 允许基类引用指向从该基类派生而来的任何类型。
11. 假设定义了一个函数,它将基类对象作为参数(即函数按值传递基类对象)。为什么该函数也可以将派生类对象作为参数?
按值传递对象将调用复制构造函数,由于形参是基类对象,因此将调用基类的复制构造函数,复制构造函数已基类引用为参数,该引用可以将指向作为参数传递的派生对象,最终的结构是,将生成一个新的基类对象,其成员对应于派生类对象的基类部分。
12. 为什么通常按引用传递对象比按值传递对象的效率更高?
按引用传递对象,这样可以确保函数从虚函数受益。另外,按引用传递对象可以节省内存和时间,尤其对于大型对象。按值传递对象的主要有点在于可以保护原始数据,但可以通过将引用作为const类型传递,来达到同样的目的。
13. 假设Corporation是基类,PublicCorporation是派生类。再假设这两个类都定义了head()函数,ph是指向Corporation类型的指针,且被赋给了一个PublicCorporation对象的地址。如果基类将head( )定义为:
a. 常规非虚方法;
b. 虚方法;
则ph->head()将被如何解释?
a. ph-head()
调用Corporation::head()
;
b. ph-head()
调用PublicCorporation::head()
;
14. 下述代码有什么问题?
代码语言:javascript复制class Kitchen
{
private:
double kit_sq_ft;
public:
Kitchen() { kit_sq_ft = 0.0; }
virtual double area() const { return kit_sq_ft * kit_sq_ft; }
};
class House : public Kitchen
{
private:
double all_sq_ft;
public:
House() { all_sq_ft = kit_sq_ft;}
double area(const char *s) const { cout << s; return all_sq_ft; }
};
首先,这种情况不符合is-a
模型,因此公有继承不适用。其次,House中area()
定义成带参数的,将隐藏area()
的Kitchen
版本。
编程练习
1. 以下面的类声明为基础:
代码语言:javascript复制// base class
class Cd { // represents a CD disk
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(char * s1, char * s2, int n, double x);
Cd(const Cd & d);
Cd();
~Cd();
void Report() const; // reports all CD data
Cd & operator=(const Cd & d);
};
派生出一个Classic类,并添加一组char成员,用于存储指出CD中主要作品的字符串。修改上述声明,使基类的所有函数都是虚的。如果上述定义声明的某个方法并不需要,则请删除它。使用下面的程序测试您的产品:
代码语言:javascript复制#include <iostream>
using namespace std;
#include "classic.h" // which will contain #include cd.h
void Bravo(const Cd & disk);
int main()
{
Cd c1("Beatles", "Capitol", 14, 35.5);
Classic c2 = Classic("Piano Sonata in B flat, Fantasia in C",
"Alfred Brendel", "Philips", 2, 57.17);
Cd *pcd = &c1;
cout << "Using object directly:n";
c1.Report(); // use Cd method
c2.Report(); // use Classic method
cout << "Using type cd * pointer to objects:n";
pcd->Report(); // use Cd method for cd object
pcd = &c2;
pcd->Report(); // use Classic method for classic object
cout << "Calling a function with a Cd reference argument:n";
Bravo(c1);
Bravo(c2);
cout << "Testing assignment: ";
Classic copy;
copy = c2;
copy.Report();
return 0;
}
void Bravo(const Cd & disk)
{
disk.Report();
}
classic.h:
代码语言:javascript复制// base class
class Cd { // represents a CD disk
private:
char performers[50];
char label[20];
int selections; // number of selections
double playtime; // playing time in minutes
public:
Cd(char* s1, char* s2, int n, double x);
Cd(const Cd& d);
Cd();
virtual ~Cd();
virtual void Report() const; // reports all CD data
virtual Cd& operator=(const Cd& d);
};
class Classic : public Cd {
private:
char* primary_work;
public:
Classic(char* sc, char* s1, char* s2, int n, double x);
Classic(const Classic& c);
Classic();
virtual ~Classic();
virtual void Report() const;
virtual Classic& operator=(const Classic& c);
};
classic.cpp:
代码语言:javascript复制#include "classic.h"
#include <cstring>
#include <iostream>
Cd::Cd(char* s1, char* s2, int n, double x) {
std::strncpy(performers, s1, 50);
std::strncpy(label, s2, 20);
selections = n;
playtime = x;
}
Cd::Cd(const Cd& d) {
std::strncpy(performers, d.performers, 50);
std::strncpy(label, d.label, 20);
selections = d.selections;
playtime = d.playtime;
}
Cd::Cd() {
performers[0] = '