继承(二)

重定义与重载

隐藏基类成员函数

重载与隐藏

重载虚函数成员支持多态性;隐藏函数成员破坏多态性。

显式调用基类函数成员的方法:

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;
}


因为有虚函数成员的对象必须维护 v-table, 虚函数成员会带来一定数量的开销。
如果任何函数成员是虚的,就要使用需析构函数。
不要把构造函数标记为虚的。

posted on 2005-04-28 18:07  NeilChen  阅读(714)  评论(2编辑  收藏  举报

导航