我目前正在研究多态类型和赋值操作之间的相互作用。我主要关心的是某人是否可能尝试将基类的值分配给派生类的对象,这会导致问题。检测基类的派生指向派生类
从this answer我了解到,基类的赋值运算符总是被隐式定义的派生类的赋值运算符隐藏起来。所以对于赋值给一个简单的变量,不正确的类型会导致编译器错误。
class A { public: int a; };
class B : public A { public: int b; };
int main() {
A a; a.a = 1;
B b; b.a = 2; b.b = 3;
// b = a; // good: won't compile
A& c = b;
c = a; // bad: inconcistent assignment
return b.a*10 + b.b; // returns 13
}
分配的这种形式可能会导致inconcistent对象的状态,但没有编译器警告和代码看起来为非作恶对我来说是第一次:但是,如果通过引用发生转让,这是不正确的一目了然。
是否有任何成熟的习惯用法来检测此类问题?
我想我只能希望运行时检测,如果我发现这样一个无效的任务会抛出异常。我现在可以想到的最佳方法是基类中的用户定义的assigment运算符,它使用运行时类型信息来确保this
实际上是指向基本实例的指针,而不是派生类,然后做一个手动的逐个成员的副本。这听起来像是很多开销,严重影响了代码的可读性。有什么更容易吗?
编辑:由于某些方法的适用性似乎取决于我想要做什么,下面是一些细节。
我有两个数学概念,说ring和field。每个领域都是一个环,但不是相反。每个实现有几个实现,它们共享公共基类,即AbstractRing
和AbstractField
,后者从前者派生。现在我尝试实现易于编写的基于std::shared_ptr
的引用语义。所以我的Ring
类包含一个std::shared_ptr<AbstractRing>
持有它的实现,和一堆转发到该方法。我想写Field
从Ring
继承,所以我不必重复这些方法。特定于某个字段的方法只需将指针投射到AbstractField
,我想这样做是静态地进行投射。我可以确保指针在施工时实际上是AbstractField
,但我担心有人会将Ring
分配给Ring&
,这实际上是Field
,因此打破了我对所包含的共享指针的假定不变性。
这里不是真正的问题,你有一个非抽象的基类吗? – 2014-08-28 11:01:29
个人而言,我禁用了多态类型的复制构造函数和赋值运算符。继承基础多态性实际上不能很好地处理值类型。 – 2014-08-28 11:10:17
@OliCharlesworth:我不明白。想想如何一个从按钮派生的切换按钮,我可以看到基类应该可实例化的情况,这个问题可能出现在现实世界中。因此我不会遵循任何“所有基础都必须抽象”的方法。如果这不是你想到的,那么请详细说明抽象基类如何能够帮助我解决问题。 – MvG 2014-08-28 11:10:21