我有一个关于operator=
的问题,该问题接受父引用类型。
当有一个抽象类及其实现类时,
为什么仅凭一个operator=
就可以接受父级引用类型呢?
下面是我的代码
#include <iostream>
class AbstractType {
public:
virtual ~AbstractType() {}
virtual AbstractType& operator=(const AbstractType& other) {
std::cout << "AbstractType& operator=(const AbstractType&)" << std::endl;
return *this;
}
};
class Type1: public AbstractType {
public:
virtual ~Type1() {}
virtual Type1& operator=(const AbstractType& other) {
std::cout << "Type1& operator=(const AbstractType&)" <<
std::endl;
return *this;
}
/*
virtual Type1& operator=(const Type1& other) {
std::cout << "Type1& operator=(const Type1&)" << std::endl;
// Just redirecting here! What a waste!
return operator=(dynamic_cast<const AbstractType&>(other));
}
*/
};
int main()
{
Type1 t1;
AbstractType& r1 = t1;
Type1 t2;
AbstractType& r2 = t2;
// Type1& operator=(const AbstractType&). It's fine!
r1 = r2;
// AbstractType& operator=(const AbstractType&)!! Why??
// Expected `Type1& operator=(const AbstractType&)` to be called!
t1 = t2;
return 0;
}
您可以发现Type1& operator=(const Type1&)
中只是重定向给定的参数,而该注释被注释忽略了。
取消注释Type1& operator=(const Type1&)
仅对我有用,
但是如果说,我有一百多个TypeX,那么我必须进行200个拷贝分配,这是我无法理解的,因为在我看来,仅拥有Type1& operator=(const AbstractType& other)
就足够了。
大多数情况下,我只有AbstractType来处理周围的事情。 很少会在有限的情况下提前知道它的特定类型。
有人可以建议我更好的解决方法吗?
答案 0 :(得分:2)
// AbstractType& operator=(const AbstractType&)!! Why?? // Expected `Type1& operator=(const AbstractType&)` to be called! t1 = t2;
您在这里打电话:
t1.operator=(t2);
由于t1
和t2
具有Type1
,因此编译器将匹配以下函数:
Type1 & Type1::operator=(const Type1 &);
是隐式定义的副本分配运算符,它将调用基础的副本分配运算符:
AbstractType & AbstractType::operator=(const AbstractType &);
但是,此调用不会动态调度-这就是您最终看到结果的原因。
取消注释
Type1& operator=(const Type1&)
仅对我有用
请注意:
dynamic_cast
。virtual
。换句话说,您可以简化为:
Type1& operator=(const Type1& other)
{
return Type1::operator=(static_cast<const AbstractType&>(other));
}
答案 1 :(得分:0)
由于Liskovs substitution principle,它指出如果程序,模块或函数正在使用基类,则可以用派生类替换基类的引用,而不会影响程序的功能。因此,在您的特定情况下,以Curiously recurring template pattern的方式实施将是一个很好的解决方案。有关更多信息,请参见link!