C++ 如何使用重写函数中的子类引用重写纯虚函数

C++ 如何使用重写函数中的子类引用重写纯虚函数,c++,overriding,abstract-class,virtual-functions,C++,Overriding,Abstract Class,Virtual Functions,因此,我在重写派生类中的纯虚函数时遇到了一个问题。 类的实现和声明如下所示: 类基{ 私人: 尺寸标识; 公众: 虚拟布尔相等(const Base&src)const=0; }; 派生类:公共基{ 私人: 字符串str; 公众: 虚拟布尔isEqual(常量派生和src)常量重写 { 返回(this->str==src.str); } }; 所以,当我像这样实现它时,我会遇到编译器错误,比如 member function declared with 'override' does not

因此,我在重写派生类中的纯虚函数时遇到了一个问题。 类的实现和声明如下所示:

类基{
私人:
尺寸标识;
公众:
虚拟布尔相等(const Base&src)const=0;
};
派生类:公共基{
私人:
字符串str;
公众:
虚拟布尔isEqual(常量派生和src)常量重写
{
返回(this->str==src.str);
}
};
所以,当我像这样实现它时,我会遇到编译器错误,比如

member function declared with 'override' does not override a base class member function

你能告诉我怎样才能做到这一点,也许能解释一下为什么我的版本不起作用。提前谢谢

多态性的原理是
派生的
基的
。如果要重写函数,则签名必须相同

解决问题的正确方法是将覆盖定义为等同于:

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派生::isEqual(const Base&src)const
{
尝试
{
派生&d=动态浇筑(src);
返回(this->str==d.str);
}
捕获(常数标准::坏的\u铸件和e)
{
//src不是派生的
返回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);
}
bool派生::isEqual(const Base*src)const
{
const-Derived*d=动态_-cast(src);
如果(d==nullptr)//src不是派生的*
返回false;
其他的
返回(this->str==d->str);
}
当然,它假设您在
Base
中有一个匹配的定义要覆盖



@Aconcagua提供的解决方案以更优雅的方式使用了相同的思想。我建议使用他的解决方案。

,您不能以这样的方式更改函数签名——请阅读有关详细信息的内容,以及为什么C++不允许同时使用函数参数(允许使用协变返回类型)。p> 另一方面,如果通过对base的引用引用另一个对象,则根本不会调用重写(实际上是:重载!)函数:

Derived d1;
Derived d2;
Base& b2 = d2;

d1.isEqual(b2); // how do you imagine the derived version to get called now???
解决方案的关键在于
动态\u 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;
    }
};
编辑:


老师告诉我们不能让操作员超负荷工作


好吧,那就恢复重命名吧。。。实际上,运算符与其他任何运算符一样都是普通函数,只是调用语法不同(实际上:存在一个替代变量,您可以始终以
d1.operator==(d2)
的形式调用)。

因为参数不同,所以您没有重写基类函数。要重写函数,需要指定完全相同的签名。我知道参数不同,但是我需要让它们不同,因为基类中不包含
字符串str
数据成员,编译器会在我的isEqual重写成员函数中抛出一个错误…所以我想我应该重载函数并删除使其成为纯虚拟函数的
=0
部分??VissarionMoutafis错误,
派生的
基础
。因此,您可以使用相同的签名覆盖它(使用
常量基&
),并传递
派生的
对象将正常工作。在函数体中,您可以
动态\u cast
。如果失败,您可以抛出异常或您想要的任何东西(给定的错误类型,
派生的
预期的。。。。或者在给定的情况下只返回false:如果类型不匹配,对象也不能相等。@VissarionMoutafis只有在
dynamic_cast
失败时才返回false。如果是这样,则对象类型不同,它们不能相等。否则,您将返回字符串比较的结果,就像您现在想要的那样。如果我们有另一个派生类,如
Derived2
,如果您传递的对象是
Derived2
,程序将崩溃!我认为最好有一个肮脏的解决方案,而不是向用户提供crash@rezaebrh事实并非如此。你为什么这么想?你已经用过了吗?它不会在所有情况下都返回false@您提供的链接中的rezaebrh由于缺少空指针检查而崩溃。这样的一个应用在这个答案中,所以一切都很好。@rezaebrh这些是必须单独解决的正交问题,例如。G正确的线程同步。但这超出了这个问题的范围……”老师告诉我们不能重载运算符”-实际上最好的方法是使用外部函数
bool operater==(const Base&rhs,const Base&lhs){return rhs.isEqual(lhs);}
-当存在从其他对象到基对象或派生对象的转换运算符时,这会更好地工作。哇,你找到了这个。我很惊讶,您无法使用派生类实现带有签名的虚拟函数。派生类是一个超集,因此它应该可以随时用作其基类。在C++中,它对其他所有的事物都是这样的。将基类向上强制转换为派生类永远感觉不到正确。@确切地说,JoeC:派生类的实例构成基类实例的子集!想象一个基类
Cat
和派生类
Lion
Tiger
Cheetah
。所有派生类都是
Cat
s,但并非所有
Cat
s都是
Tiger
s。如果现在另一个基类接受
Cat
s,而派生类只接受
Tiger
s,则基类可以接受
Lion
s,但派生类不能。因此,要实现的接口仍然不完整。返回派生类型而不是基类型(协变返回值)是类型安全的(但如果按值返回,则可能会发生对象切片)。@JoeC要接受参数,我们可以在子类中使用更通用的类型,例如。G在基础中接受一个
Tiger
,但在派生(逆变参数)中接受一个
Cat
。但是我们可以使用func
bool isEqual = d1 == b2;