请考虑以下代码:
#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 类的指针。无论如何,我尝试将派生类更改为以下内容:
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需要一个引用来派生,因为在我的实际实现中,即我希望能够做到这一点:
Derived d1;
Derived d2;
d1.foo(d2, 0, 1);
此外,我可能应该更清楚地了解我实际上在问什么。我意识到删除纯虚函数衰减
virtual void foo(Base&, const int&, const int&) const = 0;
修复了此问题。但是,在所有派生类实现中,代码完全相同,只是第一个参数(来自 Base 的派生类)的类型不同。所以感觉应该有一个纯粹的虚函数来强制foo的存在。
问题
在基类中定义纯虚拟成员函数:
virtual void foo(Base&, const int&, const int&) const = 0;
但是您在派生的函数中提供了具有另一个签名的函数:
void foo(Derived&, const int&, const int&) const;
因此,在派生类中还有一个成员函数(重载:名称相同但参数类型不同),但仍然继承纯虚函数。 因此,派生类与基类一样抽象,不允许实例化它。
解决方案
在派生类中更改签名,使其与纯虚拟 bas e 成员函数匹配:
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;
}
最终,我遇到了这个:C++中的指针变量和引用变量有什么区别?
我的结论是,因为:
-
引用不能重新绑定,必须在初始化时绑定,然后行:
rBase = rDeriv;
仅触发 stBase 复制运算符,它不会重新绑定 rBase。
- 引用
- 可以看作是类型变量的别名 =>通过引用不可能实现多态性。