Функция виртуальной группы используется, если она не чистая?

StackOverflow https://stackoverflow.com/questions/4145915

Вопрос

C++03 3.2.2 ... Объект или не перегруженные функции используются, если его имя появляется в потенциально оцененном выражении. Функция виртуальной группы используется, если она не чистая ...

А потом позже в 3.2.3 у нас есть: Каждая программа должна содержать ровно одно определение каждой ненастроенной функции или объекта, который используется в этой программе; Никакой диагностики не требуется. Определение может появиться явно в программе, его можно найти в стандарте или пользовательской библиотеке или (при необходимости) неявно определяется (см. 12.1, 12,4 и 12,8). Встроенная функция должна быть определена в каждом блок перевода, в котором он используется.

Вдоль линий я читаю: чистая виртуальная функция не используется. ODR применяется только к функциям, которые используются. Разве это не подразумевает, что следующее было бы законным? Я предполагаю, что ответ нет, это не так, но потом я не могу понять, почему.

//x.h
struct A
{
   virtual void f() = 0;
};

//y.cpp
#include "x.h"
void A::f()
{
}

//z.cpp
#include "x.h"
#include <iostream>
void A::f()
{
   std::cout << "Hello" << std::endl;
}

//main.cpp
#include "x.h"
struct B:A
{
   virtual void f()
   {
      A::f();
   }
};

int main()
{
   A* p = new B;
   p->f();
}
Это было полезно?

Решение

Две пункты не являются взаимоисключающими. Что виртуальная функция используется, если она не чистая, не означает, что общение. Если виртуальная функция чиста, это не означает, что она обязательно не используется. Еще можно использовать «Если его имя появляется в потенциально оцененном выражении», например, в вашем примере: A::f();.

Другие советы

Этот код нарушает ODR. A :: F регулируется. Следовательно, у UB.

Несколько определений между единицами переводчиков разрешены только для следующего в соответствии с $ 3.2 / 5

Там может быть более одного определения типа класса (пункт 9), тип перечисления (7.2), встроенная функция с внешней связью (7.1.2), классный шаблон (пункт 14), нестатический шаблон функций (14.5.5) , статический элемент данных шаблона класса (14.5.1.3), функция члена шаблона класса (14.5.1.1) или специализация шаблона, для которого некоторые параметры шаблона не указаны (14,7, 14,5.4) в программе при условии, что каждый Определение появляется в другом блоке перевода и при условии удовлетворения определений удовлетворяют следующим требованиям.

Как указал @ Kharles Bailey, ваш A::f на самом деле используется, даже если это чистый виртуальный. Но это около главной точки.

Не точено, что правило одного определения не распространяется на функции, которые не используются. У нас есть:

3.2P1 Нет переводческой единицы должен содержать более одного определения любой переменной, функции, типа класса, типа перечисления или шаблона.

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

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

По крайней мере, я совершенно уверен, что это намерение. Но вы можете быть на дыре в формулировке, поскольку очень буквальное чтение не говорит нигде, что множественные разные определения одинаковой неиспользованной функции в разных единицах перевода плохо образуются.

// x.cpp
void f() {}
void g() {}

// y.cpp
#include <iostream>
void f() {
  std::cout << "Huh" << std::endl;
}
void h() {}

// z.cpp
void g();
void h();
int main() { 
  g();
  h();
  return 0;
}

Это связано, но не в теме: из цитаты, кажется, есть отверстие в стандартной установке: он также должен сказать, что используется чистый виртуальный деструктор, и, что он должен быть определен; По крайней мере, если существуют какие-либо производные классы, которые разрушаются или если деструктор такого определен, поскольку деструктор полученного класса должен вызывать основу деструктора, неявно, он делает это с помощью квалифицированного :: синтаксис ID. Определение таких деструкторов обычно обычно тривиально, но не может быть уведомлено и не может быть сгенерировано.

Class.Abstract]: «Чистая виртуальная функция должна быть определена только в том случае, если она называется, или, как если бы с (12,4), квалифицированным синтаксисом ID (5.1).

Твой A::f называется B::f, так что должно быть одно определение A::f.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top