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

Res*_*ion 9 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
};
Run Code Online (Sandbox Code Playgroud)

如果Base::foo()Derived对象上调用该对象将使其同步并且其数据将被破坏.它继承了Base数据结构及其操作,但需要执行其他操作,因此只调用Base::foo()将省略这些额外操作,因此Derived状态将被破坏.

因此我想阻止直接Base执行foo这样的:

Derived d;
d.Base::foo();
Run Code Online (Sandbox Code Playgroud)

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

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

son*_*yao 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
};
Run Code Online (Sandbox Code Playgroud)

然后

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
Run Code Online (Sandbox Code Playgroud)

  • 一般来说,隐藏非多态模板函数背后的多态性是个好主意,不仅仅是在这种情况下. (8认同)

Nia*_*all 12

您可以探索模板方法模式.它允许更好地控制所涉及方法的执行.

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
};
Run Code Online (Sandbox Code Playgroud)

使用sync()pubsync()方法可以在iostreams库中看到该模式.

要防止直接调用并保持一致状态,您需要在堆栈中的正确位置获取方法的final实现foo.如果目的是禁止从层次结构顶部直接调用,则可以向上移动_impl方法.

另请参见非虚拟接口,即NVI模式.


还要记住,重写方法不必具有与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
};
Run Code Online (Sandbox Code Playgroud)

注意:除非另有说明,否则更改访问说明符可能被认为是错误的设计 - 因此,如果您确实更改了访问说明符,那么应该有充分的理由这样做.


Ton*_*roy 8

您可以将所有foo()方法设为非public,然后virtualAbstract简单调用的类中具有非函数foo.