C ++多态性不能按预期工作

时间:2018-01-08 19:03:38

标签: c++ inheritance polymorphism covariance virtual-functions

请考虑以下代码:

#include <iostream>

class Base{
public:
    int iB;
    Base() :iB(0){};
    virtual ~Base(){}
    virtual void foo(Base&, const int&, const int&) const = 0;
};


class Derived : public Base{
public:
    int iD;
    Derived() :iD(1){};
    void foo(Derived&, const int&, const int&) const;
};
void Derived::foo(Derived& d, const int& i1, const int& i2) const{ 
    std::cout << d.iD; 
}


class BaseWrap{
public:
    BaseWrap(){};
    virtual ~BaseWrap(){};
    virtual Base* bar() const = 0;
protected:
    Base* b;
};


class DerivedWrap : public BaseWrap{
public:
    DerivedWrap(){};
    Derived* bar() const;
private:
    Derived* d;
};
Derived* DerivedWrap::bar() const { 
    return new Derived; 
}

int main(){

    return 0;
}

这会导致编译器错误“错误:抽象类类型的对象”不允许派生“纯虚函数Base :: foo”没有覆盖。 我假设由于多态性,我总是可以将指针放到一个派生类中,其中指向Base类的指针。无论如何,我尝试将Derived类更改为以下内容:

class Derived : public Base{
public:
    int iD;
    Derived() :iD(1){};
    void foo(Base&, const int&, const int&) const;
};
void Derived::foo(Base& d, const int& i1, const int& i2) const{
    std::cout << d.iD; 
}

但是,现在我收到错误“错误:类”基数“没有成员”iD“。

编辑:

foo接受ref派生,因为在我的实际实现中,即我希望能够这样做:

Derived d1;
Derived d2;
d1.foo(d2, 0, 1);

此外,我可能应该更清楚我实际要问的是什么。我意识到删除纯虚函数声明

virtual void foo(Base&, const int&, const int&) const = 0;

解决了这个问题。但是,在所有派生类实现中,代码完全相同,并且仅在第一个参数的类型(Base的派生类)中有所不同。所以感觉应该有一个纯虚函数来强制存在foo。

1 个答案:

答案 0 :(得分:1)

问题

在基类中定义纯虚拟成员函数:

virtual void foo(Base&, const int&, const int&) const = 0;

但您在派生的函数中提供了另一个签名:

void foo(Derived&, const int&, const int&) const;

因此,在派生类中还有一个成员函数(重载:同名但参数类型不同),但仍继承纯虚函数。因此派生类与基类一样抽象,并且不允许实例化它。

解决方案

在派生类中更改签名,使其与纯虚拟基本成员函数匹配:

void foo(Base&, const int&, const int&) const;

顺便说一句,无论何时使用虚函数,都要使用override关键字在编译时发现这些细微的错误,即使对于普通的虚函数也是如此:

void foo(Base&, const int&, const int&) const override;

更多信息

实际上,一旦使用Base参数定义foo(),就无法轻松使用iD成员。

第一种解决方案是使用dynamic_cast告诉您的代码基本实际上是派生对象。当然,你必须检查这个假设是否正确:

void Derived::foo(Base& d, const int& i1, const int& i2) const{ 
    Derived *dp = dynamic_cast<Derived*>(&d);
    if (dp) {
        std::cout << dp->iD; 
    }
}

然而,我不清楚为什么你首先需要这个。为什么不摆脱这个第一类型依赖参数并使用当前对象的成员变量:

void Derived::foo(const int& i1, const int& i2) const{ 
    std::cout << iD; 
}