C++ 11删除重写方法

sta*_*ism 15 c++ inheritance overriding c++11

前言:

这是一个关于在应用于覆盖继承父虚拟方法的子类时,与C++ 11一起引入的删除操作符的新含义的最佳实践的问题.

背景:

根据标准,引用的第一个用例是明确禁止某些类型的调用函数,否则转换将是隐含的,例如最新C++ 11标准草案的 §8.4.3中的示例:

struct sometype {
    sometype() = delete; // OK, but redundant
    some_type(std::intmax_t) = delete;
    some_type(double);
};
Run Code Online (Sandbox Code Playgroud)

上面的例子清晰而有目的.但是,以下示例中,通过将新运算符定义为已删除来覆盖新运算符并阻止其被调用,这让我想到了我稍后在问题部分中确定的其他方案(下面的示例来自C++的第 8.4.3节)11标准草案):

struct sometype {
    void *operator new(std::size_t) = delete;
    void *operator new[](std::size_t) = delete;
};
sometype *p = new sometype; // error, deleted class operator new
sometype *q = new sometype[3]; // error, deleted class operator new[]
Run Code Online (Sandbox Code Playgroud)

题:

通过将这种思想扩展到继承,我很好奇其他人关于以下用法示例是否是明确有效的用例或者是否是对新添加的功能的滥用不清楚的想法.请为您的答案提供理由(将提供最具说服力的推理的示例).在下面的示例中,设计尝试通过使第二个版本的库继承自第一个版本来维护两个版本的库(需要实例化库).这个想法是允许错误修复或对第一个库版本所做的更改自动传播到第二个库版本,同时允许第二个库版本只关注它与第一个版本的差异.要弃用第二个库版本中的函数,delete运算符用于禁止对重写函数的调用:

class LibraryVersion1 {
public:
    virtual void doSomething1() { /* does something */ }
    // many other library methods
    virtual void doSomethingN() { /* does something else */ }
};

class LibraryVersion2 : public LibraryVersion1 {
public:
    // Deprecate the doSomething1 method by disallowing it from being called
    virtual void doSomething1() override = delete;

    // Add new method definitions
    virtual void doSomethingElse() { /* does something else */ }
};
Run Code Online (Sandbox Code Playgroud)

虽然我可以看到这种方法有很多好处,但我认为我更倾向于认为这是对该功能的滥用.我在上面的例子中看到的主要缺陷是经典的"is-a"继承关系被打破了.我已经阅读了很多文章,强烈建议不要使用任何继承来表达"一种即使是"的关系,而是使用包含函数的组合来清楚地识别类的关系.虽然下面经常皱眉的例子需要更多的努力来实现和维护(关于为这段代码编写的行数,因为每个公开可用的继承函数必须由继承类显式调用),如上所述的删除在很多方面非常相似:

class LibraryVersion1 {
public:
    virtual void doSomething1() { /* does something */ }
    virtual void doSomething2() { /* does something */ }
    // many other library methods
    virtual void doSomethingN() { /* does something */ }
};

class LibraryVersion2 : private LibraryVersion1 {
    // doSomething1 is inherited privately so other classes cannot call it
public:
    // Explicitly state which functions have not been deprecated
    using LibraryVersion1::doSomething2();
    //  ... using (many other library methods)
    using LibraryVersion1::doSomethingN();

    // Add new method definitions
    virtual void doSomethingElse() { /* does something else */ }
};
Run Code Online (Sandbox Code Playgroud)

提前感谢您的回答,并进一步了解这种潜在的删除用例.

And*_*owl 10

C++标准的第8.4.3/2段间接禁止删除覆盖虚函数的函数:

" 除了声明它之外,隐式或显式引用已删除函数的程序是不正确的.[注意:这包括隐式或显式调用函数并形成指向函数的指针或成员指针"

通过指向基类的指针调用重写虚函数是尝试隐式调用该函数.因此,根据8.4.3/2,允许这种情况的设计是非法的.另请注意,没有符合C++ 11标准的编译器将允许您删除覆盖的虚拟函数.

更明确地说,第10.3/16段规定了同样的规定:

"具有删除定义(8.4)的函数不应该覆盖没有删除定义的函数.同样,没有删除定义的函数不应该覆盖具有删除定义的函数. "

  • 谢谢你。我不知何故错过了那颗宝石。刚刚发现另一个直接禁止它的引用:“具有删除定义(8.4)的函数不应覆盖没有删除定义的函数。同样,没有删除定义的函数不应覆盖具有删除定义的函数删除定义。” (2认同)

asc*_*ler 5

10.3p16:

具有已删除定义(8.4)的函数不应覆盖没有已删除定义的函数.同样,没有删除定义的函数不得覆盖具有已删除定义的函数.

其他答案解释了为什么相当不错,但你有官方的Thou Shalt Not.