我在理解这个问题时遇到了一些麻烦。
我有一个班级:
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");
有效。 我很想知道它失败的原因,因为对我来说两个函数都是相同的。
感谢。
答案 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
。
你做不到的,因为你不能一次改变一个对象的类型
它已经建成。
(可以创建多态行为的值类型,并且 但通过信封的某些变体支持作业 成语。这是很多工作,通常很慢,通常不值得 它)。