Sunday, December 11, 2011

Virtual Functions


12.1 — Pointers and references to the base class of derived objects


In the previous chapter, you learned all about how to use inheritance to derive new classes from existing classes. In this chapter, we are going to focus on one of the most important and powerful aspects of inheritance — virtual functions.


Pointers, references, and derived classes
It turns out that because rBase and pBase are a Base reference and pointer, they can only see members of Base (or any classes that Base inherited). So even though Derived::GetName() is an override of Base::GetName(), the Base pointer/reference can not see Derived::GetName(). Consequently, they call Base::GetName(), which is why rBase and pBase report that they are a Base rather than a Derived.



1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Base
{
protected:
    int m_nValue;
 
public:
    Base(int nValue)
        : m_nValue(nValue)
    {
    }
 
    const char* GetName() { return "Base"; }
    int GetValue() { return m_nValue; }
};
 
class Derived: public Base
{
public:
    Derived(int nValue)
        : Base(nValue)
    {
    }
 
    const char* GetName() { return "Derived"; }
    int GetValueDoubled() { return m_nValue * 2; }
};

It turns out that because rBase and pBase are a Base reference and pointer, they can only see members of Base (or any classes that Base inherited). So even though Derived::GetName() is an override of Base::GetName(), the Base pointer/reference can not see Derived::GetName(). Consequently, they call Base::GetName(), which is why rBase and pBase report that they are a Base rather than a Derived.





1
2
3
4
5
6
7
8
Cat acCats[] = { Cat("Fred"), Cat("Tyson"), Cat("Zeke") };
Dog acDogs[] = { Dog("Garbo"), Dog("Pooky"), Dog("Truffle") };
 
for (int iii=0; iii < 3; iii++)
    cout << acCats[iii].GetName() << " says " << acCats[iii].Speak() << endl;
 
for (int iii=0; iii < 3; iii++)
    cout << acDogs[iii].GetName() << " says " << acDogs[iii].Speak() << endl;

1
2
3
4
5
6
7
Cat cFred("Fred"), cTyson("Tyson"), cZeke("Zeke");
Dog cGarbo("Garbo"), cPooky("Pooky"), cTruffle("Truffle");
//分别建立 cat和dog对象  
// Set up an array of pointers to animals, and set those pointers to our Cat and Dog objects
Animal *apcAnimals[] = { &cFred, &cGarbo, &cPooky, &cTruffle, &cTyson, &cZeke };
//指向animal类的指针数组,用于存放指向每个对象的指针
for (int iii=0; iii < 6; iii++)
    cout << apcAnimals[iii]->GetName() << " says " << apcAnimals[iii]->Speak() << endl;


12.2 — Virtual functions

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
class Base
{
protected:
 
public:
    virtual const char* GetName() { return "Base"; }
};
 
class Derived: public Base
{
public:
    virtual const char* GetName() { return "Derived"; }
};
 
int main()
{
    Derived cDerived;
    Base &rBase = &cDerived;
    cout << "rBase is a " << rBase.GetName() << endl;
 
    return 0;
}
This example prints the result:
rBase is a Derived
Because rBase is a pointer to the Base portion of a Derived object, when rBase.GetName() is evaluated, it would normally resolve to Base::GetName(). However, Base::GetName() is virtual, which tells the program to go look and see if there are any more-derived versions of the function available. Because the Base object that rBase is pointing to is actually part of a Derived object, the program will check every inherited class between Base and Derived and use the most-derived version of the function that it finds. In this case, that is Derived::GetName()!

No comments:

Post a Comment