虚拟任务

时间:2012-02-29 17:50:35

标签: c++

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

我有一个班级:

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");

有效。 我很想知道它失败的原因,因为对我来说两个函数都是相同的。

感谢。

4 个答案:

答案 0 :(得分:4)

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

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

答案 1 :(得分:3)

这是经典之作。

operator=是编译器为您创建的特殊方法之一。因此,这种自动创建的方法隐藏了继承的方法。

您可以通过添加

来解决它
using StringProperty::operator=;

排到测试阶段。

答案 2 :(得分:1)

复制赋值和复制构造函数是默认情况下为Test类生成的。

其他人已经通过详细的解释打败了我的解决方案,所以我将专注于其他一些咆哮。

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

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

出于这个原因,我强烈建议您将基类设计为不可复制的,并查看虚拟克隆方法(Prototype Pattern)之类的内容,以避免这些类型的设计。基类通常需要经过适当而仔细的设计,才能成为具有多态性的基类。

答案 3 :(得分:-1)

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

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

最后一行会发生什么?我希望在*p1 == *p2之后,对某些适当的平等定义。但部分原因 *p1的“值”是它具有动态类型Derived。 你做不到的,因为你不能一次改变一个对象的类型 它已经建成。

(可以创建多态行为的值类型,并且 但通过信封的某些变体支持作业 成语。这是很多工作,通常很慢,通常不值得 它)。