带有派生类的base_class上的C ++继承和虚拟关键字

时间:2012-04-16 23:52:45

标签: c++ inheritance virtual

对不起,也许我应该以更好的方式重写我的问题。

我有一个具有函数名的基类名ABC

void saysez(ostream &os) const // this is NOT virtual!!
            { os << sez; }

和派生类名DEF也有函数名

void saysez(ostream &os) const { os << extra << " ";
                         scary::saysez(os);

因此我们可以从上面的代码中看到两者都有相同的签名。

根据我的理解,如果没有指定virtual关键字,它应该使用基类函数,但在我的演练实践中输出结果是它使用了派生函数。

所以我想知道为什么使用派生函数而不是base函数?

以下是int main

的来电
     w.saysez(cout);  cout << '\n';

w是派生类的对象。

以下是带有输出

的剪切代码的链接

http://codepad.org/Pz5jwMVP

4 个答案:

答案 0 :(得分:2)

我很难理解你的问题。虚拟关键字似乎与此问题无关。你的类女巫有一个成员函数void saysez(ostream&amp;),当你创建这个类的实例并调用w.saysez时,编译器会匹配你在巫术实现中找到的saysez的定义。

虚拟关键字在这里无关紧要。如果不想看到'Double Double'部分,那么就把它变成一个可怕的:

((scary*)&w)->saysez(cout)

你不会看到打印出'Double Double'部分。

请参阅this或关于讨论虚拟关键字的任何其他网站以获取更多信息。

答案 1 :(得分:1)

以下是您可能发布的较小样本,但仍然可以证明您的问题:

#include <iostream>
using namespace std;
#include <cstring>

class scary {
    char is[31];
    char sez[31];
public:
    scary() {
        strcpy(is, "Creep");
        strcpy(sez, "boooo");
    }
    scary(const char i[], const char s[])
    {
        strcpy(is, i); strcpy(sez, s);
    }
    virtual void sayis(ostream &os) const { os << is; }
    void saysez(ostream &os) const // this is NOT virtual!!
        { os << sez; }
};

ostream &operator<<(ostream &os, const scary &x) {
    x.saysez(os);
    os << ", said the ";
    x.sayis(os);
    return os;
}

class ghost: public scary {
public:
    ghost():scary("Ghost", "Boo!")
    {
    }
};

class witch: public scary {
    char extra[31];
public:
    witch(): scary("Witch", "Toil and Trouble") {
        strcpy(extra, "Double, Double");
    }
    void saysez(ostream &os) const {
        os << extra << " ";
        scary::saysez(os);
    }
};

int main() {
    scary s; 
    ghost g; 
    witch w;
    cout << s << '\n' << g << '\n' << w << '\n';
    return 0;
}

输出:

boooo, said the Creep
Boo!, said the Ghost
Toil and Trouble, said the Witch

witch的构造函数中,您将sez数组设置为"Toil and Trouble",然后在saysez中声明的witch中打印出extra scary并调用saysez的{​​{1}}函数打印出sez。发生这种情况是因为override non-virtual member functions可能(但不鼓励)。

答案 2 :(得分:1)

我猜w被声明为巫婆类型的元素,所以当然它会调用witch :: saysez()。但是,如果你这样做了:

scary* w2 = new witch();
w2->saysez(cout);

...然后你应该看到可怕的:: saysez()行为。

看起来你误解了非虚函数如何与继承类一起工作。可以覆盖虚拟和非虚拟功能。在类Foo的对象上,如果调用Foo :: MyNonVirtualFn(),它将只执行Foo :: MyNonVirtualFn()的主体。如果Foo有一个实现MyNonVirtualFn()的超类,或者它被调用的对象实际上是一个覆盖MyNonVirtualFn()的Foo子类的实例 - 这一切都不重要。如果函数调用是Foo :: MyNonVirtualFn(),那么这是运行的函数的版本。 (如果您没有明确说明您调用它的MyNonVirtualFn()的版本是什么版本,请使用您使用的类型推断它 - 对于指针或引用类型,这可能不完全是与对象的类型相同。)

虚函数的不同之处在于,如果在对象上调用Foo :: MyVirtualFn(),它将检查该对象是否是已覆盖MyVirtualFn()的Foo子类的实例。所以,例如:

Base* base = new Base();
Derived* derived = new Derived();
Base* derived_as_base = derived;

base->MyNonVirtualFn();  // Calls Base::MyNonVirtualFn().
derived->MyNonVirtualFn();  // Calls Derived::MyNonVirtualFn().
derived_as_base->MyNonVirtualFn();  // Calls Base::MyNonVirtualFn() because it's called on a Base*.

base->MyVirtualFn();  // Calls Base::MyNonVirtualFn().
derived->MyVirtualFn();  // Calls Derived::MyNonVirtualFn().
derived_as_base->MyVirtualFn();  // Calls Derived::MyNonVirtualFn() because it uses a lookup table.

答案 3 :(得分:1)

首先,如果我不正确理解你的问题,请纠正我。

我们使用继承有很多原因,其中之一是有效编码。例如,在您的情况下,

您希望继承类scary,这意味着您希望在派生类中具有类scary的功能。您可以复制基类中的所有成员函数,使其具有与基于调用相同的功能,但是如果您决定更改其中一个函数中的某些内容,该怎么办?你必须改变所有这些。所以它是低效的编码方式。

现在在你的课堂上,你问为什么对象w在这一行w.saysez(cout); cout << '\n';,因为类scary和具有相同成员函数的类,w应首先在其类中查找匹配,如果找不到它,它将查看基础类。因此,您的对象在其类中调用saysez成员函数。

希望这会有所帮助。