使用声明作为替代 [英] Using declaration as overrider

查看:109
本文介绍了使用声明作为替代的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们在标准中有以下简单(并稍加修改以添加main和输出)示例:

We have the following simple (and slightly modified to add main and output) example in the Standard:

struct A {
    virtual void f()
    {
        cout << "A\n";
    }
};

struct B : virtual A {
    virtual void f()
    {
        cout << "B\n";
    }
};

struct C : B, virtual A {
    using A::f;
};

int main()
{
    C c;
    c.f();              // calls B​::​f, the final overrider
    c.C::f();
    return 0;
}

从中我们可以得出一个结论,即using A::f没有提供替代程序.但是标准中的什么措辞规定了这一点?这是C ++ 17草案([class.virtual] p2)中最终替代程序的措辞:

From which we can make a conclusion that using A::f does not present an overrider. But what wording in the Standard dictates it? Here is the wording for the final overrider from the C++17 draft ([class.virtual]p2):

< ...>类对象S的虚拟成员函数C :: vf是最终的 覆盖程序,除非以S为基数的最派生类(4.5) 类子对象(如果有)声明或继承另一个成员 覆盖vf 的功能.在派生类中,如果是虚拟成员 基类子对象的功能具有多个最终重写器 该程序格式不正确.

<...> A virtual member function C::vf of a class object S is a final overrider unless the most derived class (4.5) of which S is a base class subobject (if any) declares or inherits another member function that overrides vf. In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

我无法找到替代"的实际含义.如果未定义,并且我们将任何声明都视为替代者,则应考虑using声明为替代者,因为[namespace.udecl] p2表示:

And I wasn't able to find what "overrides" actually mean. If it is not defined and we consider any declaration as an overrider then we should consider the using declaration to be an overrider since [namespace.udecl]p2 says:

每个using-declaration都是一个声明和一个成员声明,​​因此可以在类定义中使用.

Every using-declaration is a declaration and a member-declaration and can therefore be used in a class definition.

我了解标准的意图,即使用声明不引入替代程序,但是有人可以指出我在Standardese中说的实际引号吗?这是第一部分,现在到第二部分

I understand the intent of the Standard for using declaration to not introduce an overrider, but can someone point me to the actual quotes which say that in Standardese? That is the first part, now to the second one

考虑以下代码:

#include <iostream>
#include <string>

using std::cout;

class A {
public:
    virtual void print() const {
        cout << "from A" << std::endl;
    }
};

class B: public A {
public:
    void print() const override {
        cout << "from B" << std::endl;
    }
};

class C: public A {
public:
    void print() const override {
        cout << "from C" << std::endl;
    }
};

class D: public B, public C {
public:
    using C::print;
};

int main()
{
    D d{};
    d.print();
    return 0;
}

如果using声明未引入覆盖程序,则D中将有2个最终覆盖程序,因此-由于

If the using declaration doesn't introduce an overrider then we have 2 final overriders in D, hence—an undefined behavior because of

在派生类中,如果是虚拟成员 基类子对象的功能具有多个最终重写器 该程序格式不正确.

In a derived class, if a virtual member function of a base class subobject has more than one final overrider the program is ill-formed.

对吗?

推荐答案

使用声明(尽管就声明区域而言确实是一个声明)不是函数声明.我们可以看到它是语法指定的:

A using declaration, while indeed a declaration as far as declarative regions are concerned, is not a function declaration. We can see it specified grammatically:

[dcl.dcl]

1 声明通常指定名称的显示方式解释. 声明的格式为

1 Declarations generally specify how names are to be interpreted. Declarations have the form

declaration:
  block-declaration
  nodeclspec-function-declaration
  function-definition
  template-declaration
  deduction-guide
  explicit-instantiation
  explicit-specialization
  linkage-specification
  namespace-definition
  empty-declaration
  attribute-declaration

block-declaration:
  simple-declaration
  asm-definition
  namespace-alias-definition
  using-declaration
  using-directive
  static_assert-declaration
  alias-declaration
  opaque-enum-declaration

nodeclspec-function-declaration:
  attribute-specifier-seq declarator ;

并且在某种程度上在语义上.由于以下各段详细介绍了从基类引入成员函数的using声明与派生类中的成员函数声明有何不同.

And to some extent semantically. Since the following paragraphs detail how a using declaration that introduces member functions from a base class is different to member function declarations in the derived class.

[namespace.udecl]

15 当using-declarator将声明从基类 成派生类,成员函数和成员函数模板 在派生类中重写和/或隐藏成员函数和成员 具有相同名称,parameter-type-list, 基本类别(相当)中的cv-qualification和ref-qualifier(如果有的话) 而不是冲突).此类隐藏或覆盖的声明不包括在内 从using-declarator引入的一组声明中.

15 When a using-declarator brings declarations from a base class into a derived class, member functions and member function templates in the derived class override and/or hide member functions and member function templates with the same name, parameter-type-list, cv-qualification, and ref-qualifier (if any) in a base class (rather than conflicting). Such hidden or overridden declarations are excluded from the set of declarations introduced by the using-declarator.

16 为了解决过载,的功能是 通过using声明引入到派生类中被视为 尽管他们是派生类的成员.特别是 隐式地,此参数应被视为是指向该参数的指针 派生类而不是基类.这对 函数的类型,以及在所有其他方面,函数 仍然是基类的成员.

16 For the purpose of overload resolution, the functions that are introduced by a using-declaration into a derived class are treated as though they were members of the derived class. In particular, the implicit this parameter shall be treated as if it were a pointer to the derived class rather than to the base class. This has no effect on the type of the function, and in all other respects the function remains a member of the base class.

请牢记这一点,如果您考虑到第一段的开头,则引用:

With that in mind, if one takes into account the beginning of the first paragraph you quote:

[class.virtual]

2 如果是虚拟成员函数vf在Base类中声明 在直接或间接地从Base派生的类中, 具有相同名称,参数类型列表的成员函数vf, cv资格和ref资格(或没有) 声明Base​::​vf,然后Derived​::​vf也是虚拟的 (无论是否声明),它都覆盖Base​::​vf.为了 方便起见,我们说任何虚函数都可以覆盖自身.

2 If a virtual member function vf is declared in a class Base and in a class Derived, derived directly or indirectly from Base, a member function vf with the same name, parameter-type-list, cv-qualification, and ref-qualifier (or absence of same) as Base​::​vf is declared, then Derived​::​vf is also virtual (whether or not it is so declared) and it overrides Base​::​vf. For convenience we say that any virtual function overrides itself.

我们可以看到它是一个虚拟的 function声明,它可以在基类中为虚拟函数引入重写器.而且,由于using声明不是函数声明,因此不符合条件.

We can see that it is a virtual function declaration that can introduce an overrider to a virtual function in a base class. And since a using declaration is not a function declaration, it does not qualify.

当前措辞部分来自 CWG缺陷608 .目的在于澄清该报告中存在问题的解释,并使用声明与虚函数重写器的概念进行解耦.

The current wording is in part from CWG Defect 608. It is aimed to clarify the problematic interpretation in that report, and to decouple using declarations from the notion of virtual function overriders.

关于第二个问题,在该引号中要注意的重要事项是基类 subobject .您的代码示例在D中具有两个 A子对象(该示例中的继承不是虚拟的).每个对象分别在BC中都有自己的最终替代程序.因此,无论是否在D中声明了另一个替代程序,程序都不会格式错误.

As for your second question, what's important to note in that quote is "of a base class subobject". Your code sample has two A sub-objects in D (the inheritance in that example isn't virtual). And each one has its own final overrider in B and C respectively. So the program is not ill-formed, with or without another overrider being declared in D.

您关注的段落适用于虚拟继承的情况.如果BC具有虚拟的A基,并且D从这两个继承而没有覆盖print,则程序

The paragraph you are concerned with applies to the case of virtual inheritance. If B and C had a virtual A base, and D inherited from both without overriding print, the program would be ill-formed. And a using declaration like using C::print will not make it well-formed, again due to the reasons stated above.

这篇关于使用声明作为替代的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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