Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/126.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 通过非虚拟方法的多态调用_C++_Inheritance_Polymorphism_Virtual Functions - Fatal编程技术网

C++ 通过非虚拟方法的多态调用

C++ 通过非虚拟方法的多态调用,c++,inheritance,polymorphism,virtual-functions,C++,Inheritance,Polymorphism,Virtual Functions,我对多态性有点问题。我的简单代码: 动物 class Animal { public: Animal(); Animal(const Animal& orig); virtual ~Animal(); virtual void get(); }; 动物蛋白 #include "Animal.h" #include <iostream> using namespace std; Animal::Animal() { cout <

我对多态性有点问题。我的简单代码:

动物

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

动物蛋白

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

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);
    }
}
同样显而易见的是,调用virtual get()方法会导致对具体子类的多态性调用。 我关心的是这种情况: 而不是

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

Bird* bird = factory.generateBird();
bird->get();
我们有一个指向Bird类的指针,其中get()方法未声明为virtual。输出为:

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!


对非虚函数的调用会导致对子类的虚调用,这是如何发生的? “虚拟主义”是继承的吗?如果是,是否有可能对指针类而不是实现类执行非虚拟调用

我们有一个指向Bird类的指针,其中get()方法不是虚的

那是错误的。它是虚拟的。派生类不能使虚函数成为非虚函数。这里的
virtual
关键字只是可选的,但没有效果

我们有一个指向Bird类的指针,其中get()方法不是虚的


那是错误的。它是虚拟的。派生类不能使虚函数成为非虚函数。这里的
virtual
关键字只是可选的,但没有任何效果。

简而言之,是的,
virtual
是“继承的”。换句话说,当您从基类继承时,您不能将其从
virtual
更改回非virtual。这会使系统很容易出现拼写错误(忘记虚拟,然后根据到达对象的路线突然调用不同的成员)

简而言之,是的,
virtual
是“继承的”。换句话说,当您从基类继承时,您不能将其从
virtual
更改回非virtual。这会使系统很容易出现拼写错误(忘记虚拟,然后根据到达对象的路线突然调用不同的成员)

A
virtual
方法在继承的类中保持
virtual
,即使您没有指定
virtual
关键字。实际上,在C++11中,您有一种方法可以指定重写该方法:

class Bird {
  void get() override;
}
您甚至可以在重写的方法上指定virtual关键字,只是为了自己记住它,但不能“删除”方法的动态分派

您唯一可以做的就是通过指定来选择实现:

Bird *bird = new Bird();
bird->Animal::get();

即使未指定
virtual
关键字,继承类中的
virtual
方法仍保留
virtual
。实际上,在C++11中,您有一种方法可以指定重写该方法:

class Bird {
  void get() override;
}
您甚至可以在重写的方法上指定virtual关键字,只是为了自己记住它,但不能“删除”方法的动态分派

您唯一可以做的就是通过指定来选择实现:

Bird *bird = new Bird();
bird->Animal::get();

假设您有一个类层次结构

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();    
};
一旦遍历层次结构,一个成员被声明为虚拟的,对于进一步的派生类也是如此。如果您想知道,如果
Q::f()
是虚拟的,那么就没有办法使
Z::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()被重写


另请参见相关问题。

假设您有一个类层次结构

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();    
};
一旦遍历层次结构,一个成员被声明为虚拟的,对于进一步的派生类也是如此。如果您想知道,如果
Q::f()
是虚拟的,那么就没有办法使
Z::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()被重写


另请参见相关问题。

是否检查了最后几行代码是否符合预期。我相信无论如何都会有一个虚拟的调度。@RalphTandetzky在那个场景中没有虚拟调度。示例:。出于同样的原因,在
derived::foo
中调用
base::foo()
不会调用虚拟调度(想象一下它说
this->base::foo()
)。顺便问一句,是否可以用Java做同样的事情?您是否检查了最后一行代码是否符合预期。我相信无论如何都会有一个虚拟的调度。@RalphTandetzky在那个场景中没有虚拟调度。示例:。出于同样的原因,在
derived::foo
中调用
base::foo()
不会调用虚拟调度(想象一下它说
this->base::foo()
)。顺便问一下,Java也可以做同样的事情吗?是的,我的错误,我的意思是“未声明”。是的,我的错误,我的意思是“未声明”。请尽量减少示例:-)请尽量减少示例:-)
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 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()