Использование 'override' для функции, которая была объявлена с помощью 'typedef'

C++ 11 представил спецификатор переопределения для функций, и я нахожу его полезным, поскольку он делает его явным, что виртуальная функция переопределяется. Однако я не могу заставить его работать для функции, которая была объявлена с использованием 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

EDIT: Чтобы ответить на комментарии, я понимаю, что этот стиль неясен. Меня больше интересует, почему это не будет компилироваться и что именно "переопределяет" (особенно потому, что это не ключевое слово). В стороне, я чувствую, что функции typedef-ing могут быть ясными в некоторых случаях, скажем:

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

Это трудно читать, особенно если это происходит часто. Я могу просто напечатать это как "UpdateAddressFunction", а затем мысленно подумать о каждой функции этого типа как о том, что "обновляет адрес".

Ответ 1

Я понимаю, что "переопределение" не является ключевым словом, имеет ли он какое-то отношение к этому?

Это означает: override признается только в нескольких конкретных контекстах и доступно в качестве имени для обычного использования в противном случае. Тем не менее, я считаю, что это ошибка компилятора, и это один из контекстов, где компилятор должен распознавать его в своем особом значении.

Соответствующее грамматическое производство для этого

[Class.mem]

член-описатель:
declarator virt-specifier-seq opt pure-specifier opt

Это не требует, чтобы спецификатор virt-seq появился только в объявлении, содержащем параметры. Единственное подобное требование указано ниже:

[Class.mem] P8:

Спецификатор virt-seq должен появляться только в объявлении виртуальной функции-члена (10.3).

В вашем случае объявление является одной из виртуальных функций-членов. Я считаю, что override должно быть принято здесь.