标记函数的正确方法是什么只是为了覆盖?

时间:2016-02-15 18:47:47

标签: c++

我有一个类,可以按原样使用或由第三方软件继承。它有一个函数Resize,对于毫无戒心的开发人员来说可能看起来很有吸引力和直接,但它只能从一个内部调用,需要事先进行特殊准备。

它是一个单独的函数的唯一原因是因为它是虚拟的并且在第三方继承类需要在此函数的内容之前和之后执行操作时被覆盖。

有没有办法只在覆盖时标记它?所以你实际上不能去MyClass.Resize()

4 个答案:

答案 0 :(得分:1)

如果只应从继承类中调用它,请将其标记为受保护。即:

class Base {
public:
  // ...

protected:
  virtual void Resize(...);

private:
  // ...
};

这意味着只有从类继承的类和类本身才能访问该函数。如果您的继承类没有/不应该直接调用该函数,而只是提供实现,您甚至可以将其标记为私有,请参阅http://www.gotw.ca/publications/mill18.htm以进行讨论。

答案 1 :(得分:1)

提供此级别控制的选项很少。最简单的方法是提供受保护的虚拟成员;

class MyClass {
protected:
  virtual void Resize(); /* =0*/
};

根据您的要求,您可能希望将其作为纯虚函数来强制派生类重写函数(注意;即使它是纯函数,您仍然可以提供函数的实现,派生类需要显式调用它来获取默认功能)。

另一种方法是在调用Resize方法之前和之后提供需要在基类中重写的另外两个函数,即template method pattern。此模式也用于标准iostreams库中,用于sync()等方法。

答案 2 :(得分:1)

我有时做的事情(为了保护用户免受他们自己)是这样的:

struct MyClass
{
private:
    virtual void PreResize() { }
    virtual void PostResize() { }
    void Resize()
    {
        PreResize();

        //TODO: necessary Resize code here

        PostResize();
    }
};

struct YourClass
{
    virtual void PostResize()
    {
        //TODO: specialized code to run after Resize logic called
    }
};

这个方案绝对保证在调用Resize时运行必要的代码。

我这样做的原因是它消除了用户是否需要知道是否在其重载函数中调用MyClass::Resize

答案 3 :(得分:0)

如果您的功能不应该从课堂外调用,您可以将其设为私有。

C ++完全支持覆盖私有成员函数:

struct Base {
    void Foo() {
        resize();
    }
private:
    virtual void resize() {
        std::cout << "Called Base::resize()" << std::endl;
    }
};


struct Derived : Base { 
private:
    virtual void resize() override {
        std::cout << "Called Derived::resize()" << std::endl;
    }
};

输出:

Called Derived::resize()