如何在重写函数中使用子类引用重写纯虚函数
How to override a pure virtual function using a subclass reference in the overriden function
所以我在派生 class 中覆盖纯虚函数时遇到问题。
classes 的实现和声明如下所示:
class Base{
private:
size_t id;
public:
virtual bool isEqual(const Base& src) const =0;
};
class Derived: public Base{
private:
string str;
public:
virtual bool isEqual(const Derived& src) const override
{
return (this->str == src.str);
}
};
所以当我这样实现它时,我遇到了编译器错误,例如
member function declared with 'override' does not override a base class member function
你能告诉我如何才能做到这一点吗,也许可以解释一下为什么我的版本不起作用。提前致谢!
多态的原理是一个Derived
是一个Base
。如果要覆盖函数,签名必须相同。
解决您的问题的正确方法是将您的替代定义为等同于:
bool Derived::isEqual(const Base & src) const
{
try
{
Derived & d = dynamic_cast<Derived &>(src);
return (this->str == d.str);
}
catch(const std::bad_cast & e)
{
// src is not a Derived
return false;
}
}
如果你想使用指针,你可以按照下面的方式做同样的事情:
bool Derived::isEqual(const Base * src) const
{
const Derived * d = dynamic_cast<const Derived*>(src);
if(d == nullptr) // src is not a Derived*
return false;
else
return (this->str == d->str);
}
当然,它假设您在 Base
中有一个匹配的定义可以覆盖。
@Aconcagua提供的解决方案以更优雅的方式使用了相同的想法。我建议改用他的解决方案。
您不能以这种方式更改函数签名 - 阅读有关 co- and contravariance 的详细信息以及为什么 C++ 不允许函数 参数 (协变 return 类型是允许)。
另一方面,如果另一个对象是通过引用 base 引用的,则根本不会调用覆盖(实际上:重载!)函数:
Derived d1;
Derived d2;
Base& b2 = d2;
d1.isEqual(b2); // how do you imagine the derived version to get called now???
解决方案的关键是 dynamic_cast
:
struct Base
{
virtual ~Base() { }
virtual bool operator==(Base const& other) = 0;
};
struct Derived : Base
{
bool operator==(Base const& other) override
{
auto o = dynamic_cast<Derived const*>(&other);
return o && o->str == this->str;
}
};
注意我把函数重命名为operator==
;这在 C++ 中更为自然。这样,您可以在上面的示例中与以下内容进行比较:
bool isEqual = d1 == b2;
编辑:
The teacher told us that we must not overload operator
好吧,然后恢复重命名...实际上,运算符与其他任何函数一样都是普通函数,只是调用语法不同(实际上:存在替代变体,您总是可以调用 d1.operator ==(d2)
, 也是).
所以我在派生 class 中覆盖纯虚函数时遇到问题。 classes 的实现和声明如下所示:
class Base{
private:
size_t id;
public:
virtual bool isEqual(const Base& src) const =0;
};
class Derived: public Base{
private:
string str;
public:
virtual bool isEqual(const Derived& src) const override
{
return (this->str == src.str);
}
};
所以当我这样实现它时,我遇到了编译器错误,例如
member function declared with 'override' does not override a base class member function
你能告诉我如何才能做到这一点吗,也许可以解释一下为什么我的版本不起作用。提前致谢!
多态的原理是一个Derived
是一个Base
。如果要覆盖函数,签名必须相同。
解决您的问题的正确方法是将您的替代定义为等同于:
bool Derived::isEqual(const Base & src) const
{
try
{
Derived & d = dynamic_cast<Derived &>(src);
return (this->str == d.str);
}
catch(const std::bad_cast & e)
{
// src is not a Derived
return false;
}
}
如果你想使用指针,你可以按照下面的方式做同样的事情:
bool Derived::isEqual(const Base * src) const
{
const Derived * d = dynamic_cast<const Derived*>(src);
if(d == nullptr) // src is not a Derived*
return false;
else
return (this->str == d->str);
}
当然,它假设您在 Base
中有一个匹配的定义可以覆盖。
@Aconcagua提供的解决方案以更优雅的方式使用了相同的想法。我建议改用他的解决方案。
您不能以这种方式更改函数签名 - 阅读有关 co- and contravariance 的详细信息以及为什么 C++ 不允许函数 参数 (协变 return 类型是允许)。
另一方面,如果另一个对象是通过引用 base 引用的,则根本不会调用覆盖(实际上:重载!)函数:
Derived d1;
Derived d2;
Base& b2 = d2;
d1.isEqual(b2); // how do you imagine the derived version to get called now???
解决方案的关键是 dynamic_cast
:
struct Base
{
virtual ~Base() { }
virtual bool operator==(Base const& other) = 0;
};
struct Derived : Base
{
bool operator==(Base const& other) override
{
auto o = dynamic_cast<Derived const*>(&other);
return o && o->str == this->str;
}
};
注意我把函数重命名为operator==
;这在 C++ 中更为自然。这样,您可以在上面的示例中与以下内容进行比较:
bool isEqual = d1 == b2;
编辑:
The teacher told us that we must not overload operator
好吧,然后恢复重命名...实际上,运算符与其他任何函数一样都是普通函数,只是调用语法不同(实际上:存在替代变体,您总是可以调用 d1.operator ==(d2)
, 也是).