继承(二)
重定义与重载
隐藏基类成员函数
重载与隐藏
重载虚函数成员支持多态性;隐藏函数成员破坏多态性。
显式调用基类函数成员的方法:
虚函数是如何工作的
vtable, vptr
虚函数仅仅对引用和指针方式传递起作用。如果以值的方式传递对象作为参数,则因为会导致转型,子类被切割(slice) 为父类的片断, 会导致错误的调用。(调用到的还是父类的方法)
虚析构函数
如果类中有任何一个函数是虚的,那它的析构函数也应当是虚的。
虚复制构造函数
有时候程序需要传递基类对象指针,并能够为派生类对象创建正确的副本。常用的解决办法是涉及到在基类中创建一个 clone 函数成员,然后使 clone 是虚的。 clone 函数成员为当前类创建新的对象副本,并返回该对象。
例子:
因为有虚函数成员的对象必须维护 v-table, 虚函数成员会带来一定数量的开销。
如果任何函数成员是虚的,就要使用需析构函数。
不要把构造函数标记为虚的。
隐藏基类成员函数
重载与隐藏
重载虚函数成员支持多态性;隐藏函数成员破坏多态性。
显式调用基类函数成员的方法:
fido.Mammal::Move(10);
虚函数是如何工作的
vtable, vptr
虚函数仅仅对引用和指针方式传递起作用。如果以值的方式传递对象作为参数,则因为会导致转型,子类被切割(slice) 为父类的片断, 会导致错误的调用。(调用到的还是父类的方法)
虚析构函数
如果类中有任何一个函数是虚的,那它的析构函数也应当是虚的。
虚复制构造函数
有时候程序需要传递基类对象指针,并能够为派生类对象创建正确的副本。常用的解决办法是涉及到在基类中创建一个 clone 函数成员,然后使 clone 是虚的。 clone 函数成员为当前类创建新的对象副本,并返回该对象。
例子:
/***************************************************
虚复制构造函数的例子
***************************************************/
#include <iostream>
using namespace std;
class Mammal
{
public:
Mammal(): itsAge(1) { cout << "Mammal constructor\n"; }
~Mammal() { cout << "Mammal destructor\n"; }
Mammal(const Mammal &rhs);
virtual void Speak() const { cout << "Mammal speak! \n"; }
// virtual constructor
virtual Mammal* Clone() { return new Mammal(*this); }
int GetAge() const { return itsAge; }
protected:
int itsAge;
};
Mammal::Mammal(const Mammal& rhs): itsAge(rhs.GetAge()) {
cout << "Mammal copy constructor\n";
}
class Dog: public Mammal
{
public:
Dog() { cout << "Dog constructor\n"; }
~Dog() { cout << "Dog destructor\n"; }
Dog(const Dog& rhs);
void Speak() const { cout << "Woof!\n"; }
virtual Mammal* Clone() { return new Dog(*this); }
};
Dog::Dog(const Dog& rhs):
Mammal(rhs) {
cout << "Dog copy constructor\n";
}
class Cat: public Mammal
{
public:
Cat() { cout << "Cat constructor\n"; }
~Cat() { cout << "Cat destructor\n"; }
Cat(const Cat&);
void Speak() const { cout << "Meow! \n"; }
virtual Mammal* Clone() { return new Cat(*this); }
};
Cat::Cat (const Cat& rhs):
Mammal(rhs) {
cout << "Cat copy constructor\n";
}
enum ANIMALS { MAMMAL, DOG, CAT };
const int NumAnimalTypes = 3;
int main(int argc, char *argv[])
{
Mammal* theArray[NumAnimalTypes];
Mammal* ptr;
int choice, i;
for (i = 0; i < NumAnimalTypes; i++) {
cout << "(1)dog (2)cat (3)Mammal: ";
cin >> choice;
switch (choice) {
case DOG:
ptr = new Dog;
break;
case CAT:
ptr = new Cat;
break;
default:
ptr = new Mammal;
break;
}
theArray[i] = ptr;
}
Mammal* OtherArray[NumAnimalTypes];
for (i = 0; i < NumAnimalTypes; i++) {
theArray[i]->Speak();
OtherArray[i] = theArray[i]->Clone();
}
for (i = 0; i < NumAnimalTypes; i++)
OtherArray[i]->Speak();
return 0;
}
虚复制构造函数的例子
***************************************************/
#include <iostream>
using namespace std;
class Mammal
{
public:
Mammal(): itsAge(1) { cout << "Mammal constructor\n"; }
~Mammal() { cout << "Mammal destructor\n"; }
Mammal(const Mammal &rhs);
virtual void Speak() const { cout << "Mammal speak! \n"; }
// virtual constructor
virtual Mammal* Clone() { return new Mammal(*this); }
int GetAge() const { return itsAge; }
protected:
int itsAge;
};
Mammal::Mammal(const Mammal& rhs): itsAge(rhs.GetAge()) {
cout << "Mammal copy constructor\n";
}
class Dog: public Mammal
{
public:
Dog() { cout << "Dog constructor\n"; }
~Dog() { cout << "Dog destructor\n"; }
Dog(const Dog& rhs);
void Speak() const { cout << "Woof!\n"; }
virtual Mammal* Clone() { return new Dog(*this); }
};
Dog::Dog(const Dog& rhs):
Mammal(rhs) {
cout << "Dog copy constructor\n";
}
class Cat: public Mammal
{
public:
Cat() { cout << "Cat constructor\n"; }
~Cat() { cout << "Cat destructor\n"; }
Cat(const Cat&);
void Speak() const { cout << "Meow! \n"; }
virtual Mammal* Clone() { return new Cat(*this); }
};
Cat::Cat (const Cat& rhs):
Mammal(rhs) {
cout << "Cat copy constructor\n";
}
enum ANIMALS { MAMMAL, DOG, CAT };
const int NumAnimalTypes = 3;
int main(int argc, char *argv[])
{
Mammal* theArray[NumAnimalTypes];
Mammal* ptr;
int choice, i;
for (i = 0; i < NumAnimalTypes; i++) {
cout << "(1)dog (2)cat (3)Mammal: ";
cin >> choice;
switch (choice) {
case DOG:
ptr = new Dog;
break;
case CAT:
ptr = new Cat;
break;
default:
ptr = new Mammal;
break;
}
theArray[i] = ptr;
}
Mammal* OtherArray[NumAnimalTypes];
for (i = 0; i < NumAnimalTypes; i++) {
theArray[i]->Speak();
OtherArray[i] = theArray[i]->Clone();
}
for (i = 0; i < NumAnimalTypes; i++)
OtherArray[i]->Speak();
return 0;
}
因为有虚函数成员的对象必须维护 v-table, 虚函数成员会带来一定数量的开销。
如果任何函数成员是虚的,就要使用需析构函数。
不要把构造函数标记为虚的。