多型體驗,和探索爺爺類指標的多型性

一匹夫發表於2020-10-03

 

1. 多型初體驗

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:

    virtual void print()
    {
        cout << "I'm Parent." << endl;
    }
};

class Child : public Parent
{
public:

    void print()
    {
        cout << "I'm Child." << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    Parent p;
    Parent*pfather = &p;

    Child c;
    Parent* pson =  reinterpret_cast<Parent*>(&c);
    Parent* p = pson;  // p也具備多型性 

    how_to_print(pfather);
    how_to_print(pson);
    how_to_print(p);

    pson_2 = pfather;
    how_to_print(p);

    return 0;
}

現象:p具備多型性
小結: 指向子類物件的父類指標被傳遞後,依然具備多型性。

 

2.  探索爺爺類的多型

實驗一:

爺爺類(父類的父類)是抽象類,看能否在孫類(子類的子類)身上,實現一個方法(成員函式)的多型呼叫。

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    virtual void print() = 0;
};

#if 0 // 方式1
class Child : public Parent
{
public:

    virtual void print() = 0;

};
#else // 方式2
class Child : public Parent
{
public:
    void print() {
        cout << "Child: print()" << endl;
    }

};
#endif

class GrandSon : public Child
{
    string name;
public:
    GrandSon(char* n_name)
    {
        name = string(n_name);
    }

    void print()
    {
        cout <<  "GrandSon::print() :" << name << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    GrandSon gson1("jason");
    how_to_print(reinterpret_cast<Parent*>(&gson1));
    Parent* pgson1 = reinterpret_cast<Parent*>(&gson1);

    cout << endl;
 
    GrandSon gson2("polly");
    Parent* pgson2 = reinterpret_cast<Parent*>(&gson2);
    how_to_print(pgson2);

    cout << endl;
    // 下面是擴充實驗
    Parent* gson_current = pgson1;
    how_to_print(gson_current);

    return 0;
}

小結: 爺爺類(父類的父類)是抽象類時,中間層的父類是抽象類也罷,或者實現了自己的多型方法也罷,此時, 當爺爺類指標指向孫類物件,依然具備多型特性。

 

實驗二:

爺爺類(父類的父類)是非抽象類,看能否在孫類(子類的子類)身上,實現一個方法(成員函式)的多型呼叫。

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    virtual void print() {
        cout << "Parent:: print()" << endl;
    }
};

class Child : public Parent
{
public:
    void print() {
        cout << "Child:: print()" << endl;
    }
};

class GrandSon : public Child
{
    string name;
public:
    GrandSon(char* n_name)
    {
        name = string(n_name);
    }
    void print()
    {
        cout << "GrandSon::print() :" << name << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    GrandSon gson1("jason");
    how_to_print(reinterpret_cast<Parent*>(&gson1));
    Parent* pgson1 = reinterpret_cast<Parent*>(&gson1);

    cout << endl;

    GrandSon gson2("polly");
    Parent* pgson2 = reinterpret_cast<Parent*>(&gson2);
    how_to_print(pgson2);

    cout << endl;
    // 下面是擴充實驗
    Parent* gson_current = pgson1;
    how_to_print(gson_current);

    return 0;
}

爺爺類是非抽象類,實現了自己的virtual的方法A,且父類也實現了自己的virtual的方法A,且子類也實現了自己的virtual的方法A, 此時, 當爺爺類指標指向孫類物件,依然具備多型特性。 

 

最終結論:

只要呼叫的成員函式自從爺爺類開始就是virtual修飾的,使用爺爺類的指標指向孫類物件時,就支援多型呼叫。 

如果你需要一個精簡版理解,那麼你只需要理解:

多型呼叫的精髓在於使用了virtual關鍵字。

 

 

 

 

 

 

.

相關文章