C++ C++;多态性未按预期工作
考虑以下代码:C++ C++;多态性未按预期工作,c++,inheritance,polymorphism,covariance,virtual-functions,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
#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;
}
此外,我可能应该更清楚我实际上在问什么。我意识到去除纯虚函数declating
virtual void foo(Base&, const int&, const int&) const = 0;
解决了这个问题。然而,在所有派生类实现中,代码都是完全相同的,只是第一个参数的类型不同(从基派生类)。所以感觉应该有一个纯虚拟函数来强制执行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;
更多信息
事实上,一旦使用基本参数定义了foo()
,就无法轻松使用iD
成员
第一种解决方案是使用动态_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派生::foo(Base&d,const int&i1,const int&i2)const{
导出*dp=动态_投射(&d);
如果(dp){
std::cout-iD;
}
}
然而,我不清楚的是,为什么你首先需要这个。为什么不去掉第一个类型相关参数并使用当前对象的成员变量:
void Derived::foo(const int& i1, const int& i2) const{
std::cout << iD;
}
void派生::foo(const int&i1,const int&i2)const{
std::cout 1)“我假设由于多态性,我总是可以将一个指向派生类的指针放在一个预期指向基类的指针上”为什么你会这样认为?2)“但是,现在我得到了错误”错误:类“Base”没有成员“iD”。Base
是否有一个名为iD
的成员?我猜您不知道:您不必将对象指定为第一个参数(如python中的self),因为它是隐式的,所以您可以直接在方法内部使用类字段。override
也会发现第一个错误。pzelasko,您是在“猜测”错误。foo在类的另一个实例上操作,而不是在*this上。正如您所看到的,bar没有DerivedWrapper的实例。但是,我失去了对iD的访问权限,因为Base没有该成员。@braaterAfrikaaner那么,您别无选择,只能使用dynamic_cast处理基类(使覆盖生效)(用于使用衍生工具的界面,如编辑的回答中所述,不包括(铸造)创建对象的副本?我将对Base的引用传递到foo的原因是因为我正在操作一个位于函数范围之外的对象。如果我创建副本,我将操作副本而不是我关心的对象。@braaterAfrikaaner不,动态\u cast不会创建对象的副本。它只返回一个指向e派生对象(如果指向对象的类型与指针的类型不匹配,则为null ptr)。因此,您可以通过此指针操作原始对象。下面是一个简短的演示:
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;
}