Разрешены ли все неиспользованные неопределенные методы?

Вот класс с неопределенным методом. Кажется, что компиляторы позволяют создавать экземпляры этого класса, если неопределенная функция-член никогда не вызывается:

struct A {
void foo();
};

int main() {
A a;      // <-- Works in both VC2013 and g++
a.foo();  // <-- Error in both VC2013 and g++
}

Вот похожая ситуация, но та, которая связана с наследованием. Подкласс Bar расширяет базовый класс Foo, Foo определяет метод g(), Bar объявляет метод с тем же именем, но не определяет его:

#include <iostream>

struct Foo {
void g() { std::cout << "g\n"; }
};

struct Bar : Foo {
void g();
};

int main() {
Bar b;      // Works in both VC2013 and g++
b.Foo::g(); // Works in both VC2013 and g++
b.g();      // Error in both VC2013 and g++
}

Вот вариант выше. Единственная разница здесь в том, что g() является virtual как для Foo а также Bar:

#include <iostream>

struct Foo {
virtual void g() { std::cout << "g\n"; }
};

struct Bar : Foo {
virtual void g();
};

int main() {
Bar b;      // Works in g++. But not in VC2013, which gives
// 'fatal error LNK1120: 1 unresolved externals'

b.Foo::g(); // Works in g++, but VC2013 already failed on b's construction
b.g();      // Error in g++, but VC2013 already failed on b's construction
}

См. Комментарии к коду для сравнения различий в поведении между VC2013 и g ++.

  1. Какой компилятор правильный, если есть?
  2. Почему у компилятора VC2013 есть несколько разных жалоб в его версии с virtual Ключевое слово по сравнению с тем в его версии без virtual ключевое слово?
  3. Всегда разрешены неиспользованные неопределенные методы? Если нет, то каковы все случаи, в которых они
    не положено?
  4. Есть ли BarВ декларации g() считаться первостепенным
    даже когда Bar не дает определения?

8

Решение

Какой компилятор правильный, если есть?

Они оба правы. Ваш код неверен, диагностика не требуется. [Class.virtual] / 11

Виртуальная функция, объявленная в классе, должна быть определена или объявлена
чистый (10,4) в этом классе или оба; но никакой диагностики не требуется
(3.2).

[Intro.compliance] / 2:

Если программа содержит нарушение правила, для которого нет диагностики
Этот международный стандарт не требует
реализации в отношении этой программы.

Посмотрите ваши настройки оптимизации для GCC, они могут влиять на поведение.


Всегда разрешены неиспользованные неопределенные методы?

Функция-член должна быть определена тогда и только тогда, когда она используется в odr. [Basic.def.odr] / 3:

Каждая программа должна содержать ровно одно определение каждого не встроенного
функция или переменная, которая используется в этой программе; нет диагностики
требуется.

Теперь рассмотрим [basic.def.odr] / 2:

Выражение потенциально оценивается если это не оцененный операнд (пункт 5) или его подвыражение.
[…] Виртуальная функция-член используется odr, если она не является чистой.
Неперегруженная функция, имя которой отображается в виде потенциально оцененного выражения или члена набора функций-кандидатов, если она выбрана разрешением перегрузки при обращении к потенциально оцененному выражению, используется odr, если только она не является чисто виртуальной Функция и ее имя явно не определены.

Вы по-прежнему можете использовать неопределенные не виртуальные функции-члены внутри decltype или же sizeof, Но не чистые виртуальные функции используются odr просто потому, что они не чистые.


Является ли объявление Bar в g () переопределением, даже если Bar
не дает определения?

Да.

8

Другие решения


По вопросам рекламы [email protected]