C ++ 11删除覆盖方法 [英] C++11 Delete Overriden Method

查看:193
本文介绍了C ++ 11删除覆盖方法的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

前言:



这是一个关于使用C ++ 11引入的delete操作符的新含义的最佳做法的问题到覆盖继承父级的虚方法的子类。




背景:



根据标准,引用的用例是明确禁止对某些类型的调用函数,否则转换将是隐式的,例如最新的C++11标准草稿

  struct sometype {
sometype()= delete; // OK,but redundant
some_type(std :: intmax_t)= delete;
some_type(double);
};

上面的例子是清楚和有目的的。但是,以下示例中,新操作符被覆盖,并通过将其定义为已删除而阻止被调用,我开始考虑我以后在问题部分中识别的其他情况(下面的示例来自 C ++ 11标准草案):

  struct sometype {
void * operator new(std :: size_t)= delete;
void * operator new [](std :: size_t)= delete;
};
sometype * p =新sometype; // error,deleted class operator new
sometype * q = new sometype [3]; //错误,删除类运算符new []



<问题:



通过将这种想法扩展到继承,我对其他人关于以下用法示例是否是一个明确和有效的用例的想法感到好奇,如果是新添加的功能的不清楚的滥用。请提供您的答案的理由(提供最引人注目的推理的示例将被接受)。在下面的示例中,设计尝试通过让库的第二个版本从第一个版本继承来维护两个版本的库(需要实例化库)。这个想法是允许错误修复或对第一个库版本所做的更改自动传播到第二个库版本,同时允许第二个库版本只关注它与第一个版本的差异。要废弃第二个库版本中的函数,使用delete操作符不允许调用重写的函数:

  class LibraryVersion1 {
public:
virtual void doSomething1(){/ *做某事* /}
//许多其他库方法
virtual void doSomethingN(){/ *做别的事* /}
};

class LibraryVersion2:public LibraryVersion1 {
public:
//通过不允许调用doSomething1方法来取消doSomething1方法
virtual void doSomething1()override = delete;

//添加新的方法定义
virtual void doSomethingElse(){/ *做别的事情* /}
};

虽然我可以看到许多好处,我想我更倾向于是滥用该功能。我在上面的例子中看到的主要缺陷是,经典的is-a继承关系被打破了。我已经阅读了许多文章,强烈建议不要使用继承来表达排序关系,而是使用组合包装函数来清楚地识别类的关系。虽然以下经常被皱眉的示例需要更多的努力来实现和维护(关于为这段代码写的行数,因为每个继承的函数都必须由继承类明确地调用),使用的删除在许多方面非常相似:

  class LibraryVersion1 {
public:
virtual void doSomethingN(){/ *做某事* /}
virtual void doSomethingN(){/ * do something * /}
//许多其他库方法
virtual void doSomethingN * do something * /}
};

class LibraryVersion2:private LibraryVersion1 {
// doSomething1是私有继承的,所以其他类不能调用
public:
//明确说明哪些函数没有被弃用
使用LibraryVersion1 :: doSomething2();
// ...使用(许多其他库方法)
使用LibraryVersion1 :: doSomethingN();

//添加新的方法定义
virtual void doSomethingElse(){/ *做别的事情* /}
};

预先感谢您的答案,并进一步了解这种潜在的使用 - 删除情况。 p>

解决方案

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



除了声明之外,引用已删除函数隐式或显式的程序还不成立。 [注意:此包括隐式调用函数或显式地形成指向函数

的成员的指针或指针

通过指向基类的指针调用覆盖的虚函数是试图隐式调用该函数。因此,根据8.4.3 / 2,允许这样做的设计是非法的。还要注意,没有符合C ++ 11的编译器会让你删除一个覆盖的虚函数。



更明确地说,第10.3 / 16段规定: >

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


Preface:

This is a question about best practices regarding a new meaning of the delete operator introduced with C++11 when applied to a child class overriding an inherited parent's virtual method.

Background:

Per the standard, the first use case cited is to explicitly disallow calling functions for certain types where conversions would otherwise be implicit such as the example from §8.4.3 of the latest C++11 standard draft:

struct sometype {
    sometype() = delete; // OK, but redundant
    some_type(std::intmax_t) = delete;
    some_type(double);
};

The above example is clear and purposeful. However, the following example where the new operator is overridden and prevented from being called by defining it as deleted started me thinking about other scenarios that I later identify in the question section (the example below is from §8.4.3 of the C++11 standard draft):

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[]


Question:

By extension of this thought to inheritance, I am curious to other's thoughts regarding whether the following usage example is a clear and valid use-case or if it is an unclear abuse of the newly added feature. Please provide justification for your answer (the example that provides the most compelling reasoning will be accepted). In the example that follows, the design attempts to maintain two versions of library (the library is required to be instantiated) by having the second version of the library inherit from the first. The idea is to allow bug fixes or changes made to the first library version to automatically propagate to the second library version while allowing the second library version to focus only on its differences from the first version. To deprecate a function in the second library version, the delete operator is used to disallow a call to the overridden function:

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 */ }
};

Though I can see many benefits to such an approach, I think I tend more toward the thought that it is an abuse of the feature. The primary pitfall I see in the above example is that the classic "is-a" relationship of inheritance is broken. I have read many articles that strongly recommend against any use of inheritance to express a "sort-of-is-a" relationship and to instead use composition with wrapper functions to clearly identify the relationships of the classes. While the following often-frowned-upon example requires more effort to implement and maintain (regarding the number of lines written for this piece of code, since every inherited function to be available publicly must be explicitly called out by the inheriting class), the use of delete as depicted above is very similar in many ways:

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 */ }
};

Thank you in advance for your answers and further insight into this potential use-case of delete.

解决方案

Paragraph 8.4.3/2 of the C++ Standard indirectly forbids deleting a function which overrides a virtual function:

"A program that refers to a deleted function implicitly or explicitly, other than to declare it, is ill-formed. [ Note: This includes calling the function implicitly or explicitly and forming a pointer or pointer-to-member to the function"

Invoking an overriding virtual function through a pointer to the base class is an attempt to implicitly invoke the function. Therefore, per 8.4.3/2, a design that allows this is illegal. Also notice that no C++11 conforming compiler will let you delete an overriding virtual function.

More explicitly, the same is mandated by Paragraph 10.3/16:

"A function with a deleted definition (8.4) shall not override a function that does not have a deleted definition. Likewise, a function that does not have a deleted definition shall not override a function with a deleted definition."

这篇关于C ++ 11删除覆盖方法的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆