如何防止调用方法的基本实现

时间:2016-04-28 08:51:43

标签: c++ inheritance

让我们说我们有以下等级:

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

理想情况下,应该给我一些编译时错误。或者什么都不做或以其他方式阻止。

然而,我可能违反了多态性规则而应该使用组合,但这需要大量额外的输入......

3 个答案:

答案 0 :(得分:22)

template method pattern

怎么样?
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类相同的访问说明符。您也可以在派生类privateprotected;

中创建方法
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

相关问题