从派生类访问虚拟基类函数

时间:2015-02-17 12:34:37

标签: c++ inheritance

1.在下面的主要函数中,为什么d.foo(9.5)没有从基类中选择Base::foo(double)方法?派生类是否继承该方法?

2.导致编译错误的原因是什么?

class Base {
public:
    virtual void foo(int){
        cout << "Base::foo(int)" << endl;
    }
    virtual void foo(double){
        cout << "Base::foo(double)" << endl;
    }
};

class Derived : public Base {
public:
    virtual void foo(int){
        cout << "Derived::foo(int)" << endl;
    }
};

void main() {
    Derived d;
    Base b, *pb = &d;

    d.foo(9);     // selects Derived::foo(int)         
    d.foo(9.5);   // selects Derived::foo(int)         
    pb->foo(9);   // selects Derived::foo(int) 
    pb->foo(9.5); // selects Base::foo(double)  

    Derived * d; 
    d->foo(9);    // compile error
}

4 个答案:

答案 0 :(得分:3)

  

在下面的主函数中,为什么d.foo(9.5)没有从基类中选择Base::foo(double)方法?派生类是否继承该方法?

是的,但它被派生类中具有相同名称的函数隐藏。您可以在派生类中使用using声明取消隐藏它:

using Base::foo;
  

导致编译错误的原因是什么?

您尝试声明名为d的第二个变量。将名称更改为尚未使用的名称;并初始化它以指向有效对象,否则您将遇到运行时错误或其他未定义的行为。

Derived * pd = &d; 
pd->foo(9);    // selects Derived::foo(int) 

此外,main的返回类型错误。它必须返回int

答案 1 :(得分:2)

1)因为这正是多态性的工作原理。如果在派生类中重新定义了虚函数,则将调用此(仅限于此)重新定义的版本。如果函数不是virtual,则反之亦然:只调用基类函数。

//Example 1: non-virtual function
class Base
{
public:
    void foo()
    {
        std::cout << "Base";
    }
}

class Derived : public Base
{
public:
    void foo()
    {
        std::cout << "Derived";
    }
}

Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Base", since the function is not virtual, and the version from the base class is called


//Example 2: virtual function
class Base
{
public:
    virtual void foo()
    {
        std::cout << "Base";
    }
}

class Derived : public Base
{
public:
    void foo()
    {
        std::cout << "Derived";
    }
}

Base * base = new Base();
base->foo()//prints "Base"
Base * derived = new Derived();
derived->foo()//prints "Derived", since the function is virtual, and the redefined version from Derived class is called

2)发生编译错误是因为你有一个冲突的声明 - 两个对象被称为d

答案 2 :(得分:2)

编译错误是因为main()中有两个同名的变量。

关于没有为Derived的实例调用的继承函数的问题(通过指向Base的指针除外)

该标准描述了&#34;隐藏规则&#34;,这使得这种情况发生。实质上,在派生类中声明的成员函数隐藏了具有相同名称但从基类继承的不同签名的继承函数。隐藏规则与继承的函数是否为虚函数无关。

常见的解决方案是使用using Base::foo引入基类中的所有继承函数。例如,

class Base {
public:
    virtual void foo(int){
        cout << "Base::foo(int)" << endl;
    }
    virtual void foo(double){
        cout << "Base::foo(double)" << endl;
    }
};

class Derived : public Base {
public:
    using Base::foo;
    virtual void foo(int){
        cout << "Derived::foo(int)" << endl;
    }
};

另一个解决方案是记住显式覆盖函数的所有继承版本(实现派生类版本以简单地调用每个函数的基类版本)。这适用于不支持上述using指令的旧编译器。问题是有必要对每个继承的重载明确地执行此操作,并且很容易错过一个。

答案 3 :(得分:1)

  Derived * d; 
  d->foo(9);    // compile error

您没有实例化对象:

派生* d =新派生;

如果你没有创建对象,编译器会使用前面的d:Derived d声明,它不是指针。