【问题标题】:Using 'override' for a function that has been declared using 'typedef'对使用 'typedef' 声明的函数使用 'override'
【发布时间】:2018-08-31 11:24:47
【问题描述】:

C++ 11 为函数引入了 'override' 说明符,我发现它很有用,因为它明确表明要覆盖虚函数。但是,我似乎无法让它适用于使用 typedef 声明的函数。

我知道“覆盖”不是关键字,它与此有关吗?

以下代码说明了我的观点:

#include <iostream>

typedef char ReturnsChar();

class Basic
{
    public:
    virtual char get_a();
    virtual ReturnsChar get_z;
};

char Basic::get_a() { return 'a'; }
char Basic::get_z() { return 'z'; }

class Capitalized : public Basic
{
    public:
    // Can override explicitly if I use the normal definition
    char get_a() override;

    // Compiles if I use the typedef but not 'override'
    ReturnsChar get_z;

    // Will not compile, but would like to do this
    //ReturnsChar get_z override; 

};

char Capitalized::get_a() { return 'A'; }
char Capitalized::get_z() { return 'Z'; }

int main()
{
    Basic foo;
    Capitalized bar;

    std::cout << foo.get_a() << std::endl; // a
    std::cout << foo.get_z() << std::endl; // z
    std::cout << bar.get_a() << std::endl; // A
    std::cout << bar.get_z() << std::endl; // Z
}

我正在使用 GNU 的 g++ 8.2.0,它给我的错误是

error: expected ';' at end of member declaration
ReturnsChar get_z override;
            ^~~~~
                      ;
error: ‘override’ does not name a type; did you mean ‘ctermid’?
     ReturnsChar get_z override;
                       ^~~~~~~~
                       ctermid

编辑:为了解决 cmets,我理解这种风格尚不清楚。我更感兴趣的是为什么这不会编译以及“覆盖”到底是做什么的(特别是因为它不是关键字)。 顺便说一句,我觉得 typedef-ing 函数在某些情况下可能很清楚,比如:

void (*foo(int x, void (*f)(int)))(int);

这很难阅读,尤其是经常出现时。我可以将其键入定义为“UpdateAddressFunction”,然后在脑海中将该类型的每个函数都视为“更新地址”。

【问题讨论】:

  • typedef 的使用确实令人困惑/不好。这使得在类中很不清楚get_z 是一个方法而不是一个变量。
  • ^ 完全同意这一点。如果您添加语言律师标签,有人可能会判断这是否符合标准,但我不想看到接受此的代码审查:P
  • 是的,在这个例子中我完全同意。但是,在我的实际用例中,我使用了一些非常复杂的函数原型和函数指针,这使得函数的类型定义很有用(我喜欢这样想)。无论哪种方式,我的问题的目的更多是为了理解为什么它不会编译,而不是样式。
  • 为什么不 typedef 只返回类型?这还不够吗?
  • @user463035818 另一个错误。 virt-specifier 甚至不允许出现在常规声明的语法中,只能出现在类中的 member-declaration 中。

标签: c++ c++11 c++14 language-lawyer


【解决方案1】:

我知道“覆盖”不是关键字,它与此有关吗?

确实如此:override 仅在少数特定上下文中被识别,并且在其他情况下可作为普通名称使用。然而,我相信这是一个编译器错误,这是编译器应该识别它的特殊含义的一个上下文。

与此相关的语法产生是

[class.mem]

成员声明符:
声明符 virt-specifier-seqopt 纯说明符opt

这并不要求 virt-specifier-seq 只出现在包含参数的声明中。唯一类似的要求如下:

[class.mem]p8:

virt-specifier-seq 应仅出现在虚成员函数 (10.3) 的声明中。

在您的情况下,声明是虚拟成员函数之一。我认为这里应该接受override

【讨论】:

  • 唯一的问题是 [lex.name]/2 "除非另有说明,否则任何关于给定 标识符 是否具有特殊含义的歧义都会被解析为将标记解释为一个常规的标识符。”我看不出代码可能会模棱两可,但我不能 100% 确定。
  • 谢谢,这很清楚。我很高兴我发现了一个实际的编译器错误,这是一个值得一提的问题!
  • @aschepler 好点。我认为有一些类似的情况是模棱两可的。我认为struct A { struct B {}; struct B override; }; 可能是一个,因为您引用的内容声明了一个名为override 的非静态数据成员。
  • @Rakete1111 我不知道这是针对我还是针对 OP,但 FWIW,我没有。在报告任何内容之前,我至少想检查一下这是否已经在最近的 GCC 9 快照上得到修复。
  • @hvd 指向你。好吧,我可以用 clang 和 gcc 主干重现。那我去报告吧。
猜你喜欢
  • 2020-05-03
  • 1970-01-01
  • 2013-05-17
  • 2021-06-27
  • 2019-06-10
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多