知识点
有如下程序
class Brass
{
private:
...
public:
...
virtual void ViewAcct() const
virtual ~Brass() {}
};
class Brass : public Brass
{
private:
...
public:
virtual void ViewAcct() const;
...
}
(1)如果通过对对象调用,程序将使用对象类型来确定哪个
Brass dom (...);
BrassPlus dot (...)
dom.ViewAcct(); // use Brass::ViewAcct
dot.ViewAcct(); // use BrassPlus::ViewAcct
(2)如果方法是通过引用或指针而不是对象调用
A. 如果没有使用virtual关键字,程序将根据引用类型或指针类型选择方法
Brass dom (...);
BrassPlus dot (...);
Brass & b1_ref = dom;
Brass & b2_ref = dot;
b1_ref.ViewAcct(); // use Brass::ViewAcct()
b2_ref.ViewAcct(); // use Brass::ViewAcct()
解释:引用变量的类型是Brass,所以选择了Brass::ViewAcct()。
B. 如果使用了virtual关键字,程序根据引用或指针指向的对象的类型来选择方法
Brass dom (...);
BrassPlus dot (...);
Brass & b1_ref = dom;
Brass & b2_ref = dot;
b1_ref.ViewAcct(); // use Brass::ViewAcct()
b2_ref.ViewAcct(); // use BrassPlus::ViewAcct()
解释:两个引用类型都是Brass,但b2_ref引用的是一个BrassPlus对象,所以使用use BrassPlus::ViewAcct()
相关问题
1 派生类从基类那里继承了什么,不能从基类那里继承什么?
答:派生类继承基类的数据成员和大部分方法,不能继承基类的构造函数、析构函数、赋值运算符、友元函数。
2 假设baseDMA::operator=()函数的返回类型为void,而不是baseDMA &,这将造成什么后果?如果返回类型为baseDMA,而不是baseDMA &,又将是什么后果?
答:返回的是void,可以进行单个赋值,但是不能进行连续赋值 ,例如a=b=c的情况;
返回的是baseDMA,可返回一个副本,增加程序时间和内存的消耗,效率降低。
3 创建和删除派生类对象时,构造函数和析构函数的调用顺序是怎样的?
答:创建派生类对象时,将首先调用基类的构造函数,然后调用派生类的构造函数;删除派生类对象时,将首先调用派生类的析构函数,然后调用基类的析构函数。
4 如果派生类没有添加任何数据成员,它是否需要构造函数?
答:需要。派生类不能继承基类的构造函数,即使自己不写,系统也会默认生成一个。
5 如果基类和派生类定义了同名的方法,当派生类对象调用该方法时,被调用的将是哪个方法?
答:只调用派生类方法。因为派生类定义的方法取代基类定义的方法;派生类的重新定义的方法应该声明为虚函数。
仅当派生类没有重新定义方法或者使用作用域解析操作符时,才会调用基类方法。
6 在什么情况下,派生类应定义赋值运算符?
答:在派生类构造函数中使用new或new[]来初始化指针成员的时候。
若在派生类构造函数中使用new或new[]来初始化指针成员,派生类还应该定义复制构造函数、显示析构函数
7 可以将派生类对象的地址赋给基类指针吗?可以将基类对象的指针赋给派生类指针吗?
答:可以将派生类对象的地址赋给基类指针。使用显示类型转换,也可以将基类对象的指针赋给派生类指针。
8 可以将派生类对象赋给基类对象吗?可以将基类对象赋给派生类对象吗?
答:可以将派生类对象赋给基类对象。派生类中新增的数据成员都不会传给基类对象。
仅当派生类定义了转换操作(即包含将基类引用作为唯一参数的构造函数)或使用基类为参数的赋值操作符,基类对象赋给派生类对象。
9 假设定义了一个函数,它将基类对象的引用作为参数。为什么该函数也可以将派生类对象作为参数?
答:因为C++允许基类引用指向该基类派生而来的任何类型。
10 假设定义了一个函数,它将基类对象作为参数(即函数按值传递基类对象)。为什么该函数也可以将派生类对象作为参数?
答:按值传递将调用复制构造函数。由于形参是基类对象,因此调用基类的复制构造函数。复制构造函数以基类引用为参数,该引用可以指向作为参数传递的派生类对象。最终结果是将生成一个基类的临时对象,其成员对应于派生类对象的基类部分。
11 为什么通常按引用传递对象比按值传递对象的效率高?
答:按值传递是建立一个临时对象,然后将参数的值复制到这个新的对象中。而引用传递则直接使用原来的对象,省去了很多的功夫。
另外如果函数内使用了对象的某个虚函数,则会优先调用派生类的函数。
12 假设Corporation是基类,PublicCorporation是派生类。再假设这两个类都定义了head()函数,ph是指向Corporation类型的指针,且被赋给了一个PublicCorporation对象的地址。如果基类将head()函数定义为:
A. 常规非虚方法;
B. 虚方法
则ph ->head()将被如何解释?
答:A 调用基类函数 ph->head()将调用Corporation::head()
B 调用派生类函数 ph->head()将调用PublicCorporation::head()
13 下属代码有什么问题
class Kitchen
{
Private:
Double kit_sq_ft;
Public:
Kitchen() {kit_sq_ft = 0.0;}
Virtual double area() const {return 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;}
};
1)首先从语义上来看,厨房和房子不是is-a关系,而是has-a关系,所以不应该使用继承,而是将Kitchen作为House的一个成员。
2)kit_sq_ft是私有成员,House中无法直接访问。
3)除了声明为成员,还可以构造一个虚基类,因为它们都有长度,面积之类的属性。
4)House的area()函数,隐藏了基类的。因为它们特征标不同。
参考
《C++ Primer Plus(第六版)》(26)(第十三章 类继承 复习题答案)
http://blog.youkuaiyun.com/u012175089/article/details/53898671
http://blog.youkuaiyun.com/u013271921/article/details/44676979