虚拟分配

virtual assignment

本文关键字:分配 虚拟      更新时间:2023-10-16

我在理解这个问题时遇到了一些麻烦。

我有一堂课:

class StringProperty { //snipped...
protected:
    std::string s;
public:
    virtual StringProperty& operator= (const std::string &x) {
        s = x;
        return *this;
    }
    virtual StringProperty& foo(const std::string &x) {
        s = x;
        return *this;
    }
};

这个类(有更多的方法,为了简单起见被截取(应该充当字符串。

当我从中得出时:

class Test : public StringProperty { };

我想做这样的事情:

Test x;
x = "test";

但是,这惨遭失败(不编译(:

error: no match for ‘operator=’ in ‘x = "test"’

尽管如此,如果我使用

x.foo("test");

它有效。我有兴趣了解它失败的原因,因为对我来说这两个函数是相同的。

谢谢。

您的Test类包含一个隐式声明的复制赋值运算符(以及默认构造函数、复制构造函数和析构函数(。这将隐藏基类中的那个。为了将其视为重载,您必须使其在派生类中可访问:

class Test : public StringProperty {
public:
    using StringProperty::operator=;
};

这是经典的。

operator= 是编译器为您创建的特殊方法之一(如果您不这样做(。因此,此自动创建的方法隐藏继承的方法。

您可以通过添加来解决它

using StringProperty::operator=;

行到类测试。

默认情况下,复制赋值和复制构造函数是为测试类生成的东西。

其他人已经通过详细的解释击败了我的解决方案,所以我将专注于其他事情。

我见过像这样的分层设计很快就会出现问题。我甚至与一位设计架构的高级开发人员合作,他甚至无法正确获得基本的数学向量库,因为他认为他可以创建一个向量基类,从中派生,向子类添加更多成员,并重用诸如从基类复制语义之类的东西(包括operator=(。可以说,他很快就遇到了切片等问题。我告诉他不要再试图以这种"扩展"的方式使用继承(子类建模看起来更像超类的东西(。像这样的问题为那些声称C++是一种糟糕的语言(例如:Linus Torvalds(的人火上浇油,因为很多人在使用它时会犯面向对象设计错误,尤其是在涉及继承时(我认为,另一个主要来源是单片类设计(。

通过基类提供给子类的赋值概念打破了多态性。想象一下,狗和猫从哺乳动物继承而来,它为两者提供了复制语义。当我们把狗复制到猫身上时会发生什么?假设我们调用某个接受哺乳动物的函数,并将Cat分配给它,但我们传入了对Dog的引用。应该发生什么?这在逻辑上是没有道理的。然而,如果 Dog 和 Cat 都使用 Mammal 的复制函数或运算符,编译器将允许这样做。

出于这个原因,我强烈建议您将基类设计为通常不可复制的,并研究虚拟克隆方法(原型模式(之类的东西,以避免这些类型的设计。基类通常需要适当且仔细地设计,以考虑多态性的基类。

值和多态性不能很好地协同工作。 症状你看到很容易修复:编译器提供的赋值运算符在派生类中隐藏基类中的任何赋值运算符。因此,您必须提供它的实现。 问题仍然存在,但是,您无法真正为其提供任何合理的语义:

Base* p1 = new Derived;
Base* p2 = new Base;
*p2 = *p1;

最后一行应该发生什么? 我希望在*p1 == *p2之后,对平等进行一些适当的定义。 但部分*p1的"值"是它具有动态类型Derived。您无法这样做,因为您无法更改对象的类型它已经建成。

(可以制作行为多态的值类型,并且然而,通过信封的某种变体支持分配成语。 这是很多工作,通常非常缓慢,通常不值得它。