C++: правильное переопределение виртуальной функции в классе шаблонов

рассмотрим следующий код:

template<typename T>
struct MyTempl
{
    virtual void doStuff(const T &value) = 0;
};

struct MyImpl : MyTempl<int>
{
    void doStuff(const int &value) {}
};

struct MyPtrImpl : MyTempl<int*>
{
    void doStuff(const int* &value) {}
};

MyImpl imp1;
MyPtrImpl imp2;

это не будет компилироваться правильно: компилятор говорит мне, что doStuff() на MyPtrImpl является чисто виртуальным, т. е. Я не смог правильно переписать. Если я, однако, typedef int* что-то вроде int_ptr, и использовать в качестве аргумента шаблона MyPtrImpl, все работает.

почему компилятор не может вычесть мое намерение без typedef?

1 ответов


вы не указали правильный тип параметра виртуальной функции и, таким образом, вы не переопределяя его. В результате абстрактный класс с виртуальной функцией чистое.

при указании параметра ссылочного типа const, например

void doStuff(const int & value) {}

это на самом деле Альтернатива для записи

void doStuff(int const & value) {}

который следует считать "нормальным" способом объявления постоянной ссылки. Если читать справа налево, это означает "ссылка на константа int". Применение того же шаблона к типу указателя int* результаты

void doStuff(int* const & value) {}

, который компилирует штрафа в размере. Но это не может быть написано в порядке, как указано выше, так как это означало бы что-то другое: read const int* & справа налево, и вы получите "ссылку на указатель на константу int".

как вы упомянули, альтернатива, которая работает с порядком сверху, может быть написана, если вы используете typedef для псевдонима указателя тип int*:

typedef int *T;
void doStuff(const T & value) {}

который также компилирует fine С T теперь рассматривается как один литеральный тип, не вводящий двусмысленности сверху. Другими словами, единственный вариант, как читать const T & это " ссылка на const T, что само по себе является указателем на int". Это немного сложно понять интуитивно, но то, что невозможно понять, это как "ссылка на указатель на константу int", так как это не было бы один T в описании.

я рекомендую использовать ключевое слово override если вы используете компилятор C++11 для обнаружения таких проблем (существуют сценарии, в которых эта проблема не приведет к ошибке компиляции, а к неожиданному поведению; например, если виртуальная функция была не чисто):

void doStuff(int* const & value) override {}
//                               ^^^^^^^^