我对多态性有一点问题。我的简单代码:
Animal.h
class Animal {
public:
Animal();
Animal(const Animal& orig);
virtual ~Animal();
virtual void get();
};
Animal.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;
}
Bird.h
class Bird : public Animal {
public:
Bird();
Bird(const Bird& orig);
virtual ~Bird();
void get();
};
Bird.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();
};
Chicken.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();
};
Factory.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&amp; 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类中删除虚拟关键字会导致调用 get()方法的Animal实现,无论animal *指向Bird还是Chicken。
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();
我们有一个指向Bird类的指针,其中 get()方法未声明为虚拟。输出是:
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!
如何实现,调用非虚函数会导致对子类的虚拟调用?
“虚拟主义”是否继承了?如果是,是否可能以某种方式对指针类执行非虚拟调用,而不是实现类?
答案 0 :(得分:4)
即使您未指定virtual
关键字,virtual
方法仍会在继承的类中保留virtual
。实际上在C ++ 11中,您可以指定该方法被覆盖:
class Bird {
void get() override;
}
您甚至可以在重写方法上指定虚拟关键字,只是为了自己记住它,但是您无法“删除”该方法的动态调度。
您唯一可以做的是通过指定它来选择实现:
Bird *bird = new Bird();
bird->Animal::get();
答案 1 :(得分:1)
我们有一个指向Bird类的指针,其中 get()方法不是虚拟的。
那是错的。这是虚拟的。虚函数不能通过派生类变为非虚函数。 virtual
关键字在那里是可选的,但它没有效果。
答案 2 :(得分:1)
简而言之,是的,virtual
是“继承的”。换句话说,当您从基类继承时,您无法从virtual
“更改回”到非虚拟。这会使系统对拼写错误非常脆弱(忘记虚拟,并且突然根据您来到对象的路线调用不同的成员)。
答案 3 :(得分:0)
假设你有一个类层次结构
class A{
void f();
};
class B : public A{
void f();
};
class C : public B{
void f();
};
\\...
class O : public N{
void f();
};
class P : public O{
virtual void f();
};
class Q : public P{
virtual void f();
};
class R : public Q{
void f();
};
\\...
class Z : public Y{
void f();
};
只要遍历层次结构,成员就被声明为虚拟成员,对于其他派生类也是如此。如果您想知道,如果Z::f()
是虚拟的,则无法使Q::f()
非虚拟。
这段代码解释了这个含义:
Z z;
A& a = z;
O& o = z;
P& p = z;
Q& q = z;
Z& z = z;
a.f(); //calls A::f()
o.f(); //calls O::f()
p.f(); //calls Z::f()
q.f(); //calls Z::f()
z.f(); //calls Z::f()
z.A::f(); //calls A::f()
z.R::f(); //calls R::f()
当然这假设O :: f()被覆盖。
另请参阅my answer相关问题。