10

我刚刚尝试了这段代码:

struct FaceOfPast
{
    virtual void Smile() = 0;
};

struct FaceOfFuture
{
    virtual void Smile() = 0;
};

struct Janus : public FaceOfPast, public FaceOfFuture
{
    virtual void Smile() {printf(":) ");}
};

...

void main()
{
    Janus* j = new Janus();
    FaceOfFuture* future = j;
    FaceOfPast* past = j;

    future->Smile();
    past->Smile();

    delete j;
}

它按预期工作(输出两个笑脸),但我认为它甚至不应该编译,重新声明Smile()Janus模棱两可的。

它如何(以及为什么)起作用?

4

3 回答 3

7

没有歧义,因为您调用Smile()了指向FaceOfFuture并且FaceOfPast只声明一个方法的指针Smile()

因为在基类指针上调用方法不会导致歧义,让我们处理直接在子类指针上调用方法的情况

Janus* j = new Janus();
j->Smile();

派生类除了重写之外,还隐藏了基类的Smile(). 只有当您不覆盖派生类中的方法时,您才会有歧义:

以下编译:

struct FaceOfPast
{
    virtual void Smile() {printf(":) ");}
};
struct FaceOfFuture
{
    virtual void Smile() {printf(":) ");}
};
struct Janus : public FaceOfPast, public FaceOfFuture
{
   virtual void Smile() {printf(":) ");}
};
int main()
{
   Janus* j = new Janus();
   j->Smile();
}

尽管您调用Smilea Janus,但基类声明是隐藏的。

以下没有:

struct FaceOfPast
{
    virtual void Smile() {printf(":) ");}
};

struct FaceOfFuture
{
    virtual void Smile() {printf(":) ");}
};

struct Janus : public FaceOfPast, public FaceOfFuture
{
};

int main()
{
   Janus* j = new Janus();
   j->Smile();
}

因为模棱两可。

于 2012-04-24T12:05:42.220 回答
1

根据 C++ 标准(10.3.2):

如果虚成员函数 vf 在类Base和类Derived中声明,直接或间接从Base派生,则具有相同名称、参数类型列表、cv 限定和 ref 限定符的成员函数vf (或没有相同的)作为Base::vf被声明,然后Derived::vf [...] 覆盖Base::vf

多重继承似乎没有任何特殊处理,因此它很可能也适用于这里:void Janus::Smile()重写这两个方法而没有任何歧义,只是因为它与两个基类方法具有完全相同的名称和签名。

于 2012-04-24T14:38:41.537 回答
0
Janus* j = new Janus();
FaceOfFuture* future = j;
FaceOfPast* past = j;

这部分代码转换为基类。因此,当您执行以下操作时

future->Smile();
past->Smile();

这实际上是指向 FaceofPast 和 FaceOfFuture 的指针。

于 2012-04-24T12:48:31.180 回答