1

ポリモーフィズムに少し問題があります。私の簡単なコード:

アニマル.h

class Animal {
public:
    Animal();
    Animal(const Animal& orig);
    virtual ~Animal();
    virtual void get();
};


アニマル.cpp

#include "Animal.h"
#include <iostream>
using namespace std;

Animal::Animal() {
    cout << "Animal is born" << endl;
}

void Animal::get() {
    cout << "get() from an Animal!" << endl;
}



鳥.h

class Bird : public Animal {
public:
    Bird();
    Bird(const Bird& orig);
    virtual ~Bird();
    void get();
};


鳥.cpp

#include "Bird.h"
#include <iostream>
using namespace std;

Bird::Bird() {
    cout << "Bird is born" << endl;
}

void Bird::get() {
    cout << "get() from a Bird!" << endl;
}



Chicken.h

#include "Bird.h"

class Chicken : public Bird {
public:
    Chicken();
    Chicken(const Chicken& orig);
    virtual ~Chicken();
    void get();
};


チキン.cpp

#include "Chicken.h"
#include <iostream>
using namespace std;

Chicken::Chicken() {
    cout << "Chicken is born" << endl;
}

void Chicken::get() {
    cout << "get() from a Chicken!" << endl;
}



入力に基づいて具体的な実装への Animal* ポインタを返すファクトリ メソッドもあります。


Factory.h

#include "Animal.h"
#include "Bird.h"

class Factory {
public:
    Factory();
    Factory(const Factory& orig);
    virtual ~Factory();
    Animal* generateAnimal();
    Bird* generateBird();
};


工場.cpp

#include "Factory.h"

#include "Animal.h"
#include "Bird.h"
#include "Chicken.h"

#include <iostream>
#include <string>
#include <stdlib.h>
using namespace std;

Animal* Factory::generateAnimal() {
    string choice;
    cout << "What do you want? 1-Animal, 2-Bird, 3-Chicken" << endl;
    cin >> choice;
    Animal* animal;

    if (choice.at(0) == '1') {
        cout << "You chose Animal" << endl;
        animal = new Animal();
        return animal;
    } else if (choice.at(0) == '2') {
        cout << "You chose Bird" << endl;
        animal = new Bird();
        return animal;
    } else if (choice.at(0) == '3') {
        cout << "You chose Chicken" << endl;
        animal = new Chicken();
        return animal;
    } else {
        cout << "Wrong input" << endl;
        exit(1);
    }
}

Bird* Factory::generateBird() {
    string choice;
    cout << "What do you want? 1-Animal, 2-Bird, 3-Chicken" << endl;
    cin >> choice;
    Bird* bird;

    if (choice.at(0) == '2') {
        cout << "You chose Bird" << endl;
        bird = new Bird();
        return bird;
    } else if (choice.at(0) == '3') {
        cout << "You chose Chicken" << endl;
        bird = new Chicken();
        return bird;
    } else {
        cout << "Wrong input" << endl;
        exit(1);
    }
}



ctors と dtors は省略しました。
main.cpp

#include <cstdlib>
#include <iostream>
#include "Factory.h"
#include "Animal.h"
#include "Bird.h"
#include "Chicken.h"

using namespace std;

int main(int argc, char** argv) {
    Factory factory;
    Animal* animal = factory.generateAnimal();
    animal->get();

    return 0;
}



Animal クラスの具体的な実装は、実行時に解決されます。Animal クラスからvirtualキーワードを削除すると、animal* が Bird または Chicken を指しているかどうかにかかわらず、get()メソッドの Animal 実装が呼び出されることは明らかです。

What do you want? 1-Animal, 2-Bird, 3-Chicken
3
You chose Chicken
Animal is born
Bird is born
Chicken is born
get() from an Animal!

また、仮想get()メソッドを呼び出すと、具体的なサブクラスへのポリモーフィック呼び出しが発生することも明らかです。私が懸念しているのは、この状況です。

Animal* animal = factory.generateAnimal();
animal->get();

我々は持っています

Bird* bird = factory.generateBird();
bird->get();

get()メソッドが virtual と宣言されていない Bird クラスへのポインタがあります。出力は次のとおりです。

What do you want? 1-Animal, 2-Bird, 3-Chicken
3
You chose Chicken
Animal is born
Bird is born
Chicken is born
get() from a Chicken!



非仮想関数への呼び出しがサブクラスへの仮想呼び出しになるのはどうしてですか? 「ヴァーチャリズム」は受け継がれる?もしそうなら、実装クラスの代わりにポインタクラスへの非仮想呼び出しを実行することはどういうわけか可能ですか?

4

4 に答える 4

4

キーワードを指定しなくても、virtualメソッドは継承されたクラスに残ります。実際、C++11 では、メソッドがオーバーライドされることを指定する方法があります。virtualvirtual

class Bird {
  void get() override;
}

自分で覚えるためだけにオーバーライドされたメソッドに virtual キーワードを指定することもできますが、メソッドの動的ディスパッチを「削除」することはできません。

許可されている唯一のことは、実装を指定して選択することです。

Bird *bird = new Bird();
bird->Animal::get();
于 2013-09-18T10:38:56.883 に答える
1

get()メソッドが仮想ではないBird クラスへのポインタがあります。

それは間違っている。仮想です。派生クラスによって仮想関数を非仮想にすることはできません。キーワードはオプションですが、virtual効果はありません。

于 2013-09-18T10:38:45.850 に答える
1

要するに、はい、virtual「継承」です。virtualつまり、基本クラスから継承する場合、非仮想から「元に戻す」ことはできません。これにより、システムはタイプミスに対して非常に壊れやすくなります (仮想を忘れて、オブジェクトに到達したルートに応じて、突然別のメンバーを呼び出します)。

于 2013-09-18T10:38:53.817 に答える