让我们说我们有以下等级:
class Abstract
{
public:
virtual void foo() = 0;
};
class Base : public Abstract
{
public:
virtual void foo() override; //provides base implementation
};
class Derived : public Base
{
public:
virtual void foo() override; //provides derived implementation
};
如果在Base::foo()
对象上调用了Derived
,该对象将会同步并且其数据将被破坏。它继承了Base
的数据结构及其操作,但需要执行其他操作,因此仅调用Base::foo()
将省略这些额外操作,因此Derived
&#39 ; s状态将被破坏。
因此,我希望阻止直接调用[{1}} Base
foo
,这样:
Derived d;
d.Base::foo();
理想情况下,应该给我一些编译时错误。或者什么都不做或以其他方式阻止。
然而,我可能违反了多态性规则而应该使用组合,但这需要大量额外的输入......
答案 0 :(得分:22)
class Abstract
{
public:
void foo() { foo_impl(); }
private:
virtual void foo_impl() = 0;
};
class Base : public Abstract
{
private:
virtual void foo_impl() override; //provides base implementation
};
class Derived : public Base
{
private:
virtual void foo_impl() override; //provides derived implementation
};
然后
void test(Abstract& obj) {
obj.foo(); // the correct foo_impl() will be invoked
}
Derived d;
test(d); // impossible to call the foo_impl() of Base
答案 1 :(得分:12)
您可以浏览template method pattern。它允许更好地控制所涉及方法的执行。
class Abstract
{
public:
virtual void foo() = 0;
};
class Base : public Abstract
{
protected:
virtual void foo_impl() = 0;
public:
//provides base implementation and calls foo_impl()
virtual void foo() final override { /*...*/ foo_impl(); }
};
class Derived : public Base
{
protected:
virtual void foo_impl() override; //provides derived implementation
};
使用sync()
和pubsync()
方法在iostreams库中看到该模式。
要防止直接调用并保持一致状态,您需要在堆栈中的正确位置获取final
方法的foo
实现。如果目的是禁止从层次结构顶部直接调用,则可以向上移动_impl
方法。
另请参阅非虚拟界面the NVI pattern。
请记住,重写方法不必具有与Abstract
类相同的访问说明符。您也可以在派生类private
或protected
;
class Abstract
{
public:
virtual void foo() = 0;
};
class Base : public Abstract
{
virtual void foo() override; //provides base implementation
};
class Derived : public Base
{
virtual void foo() override; //provides derived implementation
};
注意:除非另有说明,否则更改访问说明符可能被认为是错误的设计 - 所以基本上如果您确实更改了访问说明符,那么应该有充分的理由这样做。
答案 2 :(得分:8)
您可以将所有foo()
方法设为非public
,然后在virtual
类中使用非Abstract
函数,只需调用foo
。