Pregunta

C++03 3.2.2 ... se utiliza un objeto o función no sobrecargado, si su nombre aparece en una expresión evaluada potencialmente. Una función miembro virtual se utiliza si no es puro ...

Y más tarde en 3.2.3 tenemos: Cada programa deberá contener exactamente una definición de cada función o un objeto no en línea que se utiliza en ese programa; requerido no de diagnóstico. La definición puede aparecer de forma explícita en el programa, que se puede encontrar en el estándar o una biblioteca definida por el usuario, o (cuando sea apropiado) se define implícitamente (ver 12.1, 12.4 y 12.8). Una función en línea se definirá en cada unidad de traducción en el que se utiliza.

A lo largo de las líneas que estoy leyendo: una función virtual pura no se utiliza. El ODR se aplica sólo a las funciones que se utilizan. ¿No implica esto que la siguiente sería legal? Estoy adivinando la respuesta es no, no lo hace, pero entonces no puedo entender por qué.

//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();
}
¿Fue útil?

Solución

Los dos cláusulas no son mutuamente excluyentes. Que una función virtual se utiliza si no es puro, no significa que lo contrario se mantiene. Si una función virtual pura es no quiere decir que necesariamente no se utiliza. Todavía se puede usar "si su nombre aparece en una expresión potencialmente evaluado", como en el ejemplo:. A::f();

Otros consejos

Este código viola ODR. A :: f se define multiplican. Por lo tanto, tiene UB.

Las definiciones múltiples a través de las unidades de traducción se permite sólo para la siguiente de acuerdo con $ 3,2 / 5

  

No puede haber más de una definición   de un tipo de clase (cláusula 9),   tipo de enumeración (7.2), en línea   función con enlace externo   (7.1.2), plantilla de clase (cláusula 14),   plantilla de función no estático (14.5.5),   miembro de datos estáticos de una plantilla de clase   (14.5.1.3), la función miembro de una clase   plantilla (14.5.1.1), o plantilla   especialización para la que alguna plantilla   parámetros no se especifican (14,7,   14.5.4) en un programa a condición de que cada definición aparece en una diferente   unidad de traducción, y siempre que el   definiciones satisfacen la siguiente   requisitos.

Como @Charles Bailey señaló, su A::f de hecho se utiliza, aunque es pura virtual. Pero ese no es el punto principal.

No es preciso que la Regla Una definición no se aplica a las funciones que no se utilizan. Tenemos:

  

3.2p1 unidad de traducción no deberá contener más de una definición de cualquier variable, función, tipo de clase, tipo de enumeración o plantilla.

     

Cada 3.2p3 programa deberá contener exactamente una definición de cada función o un objeto no en línea que se utiliza en ese programa; no de diagnóstico necesarias.

En conjunto, estos requisitos parecen dar a entender que una función utilizada debe tener exactamente una definición, y una función sin usar (incluyendo una función virtual pura que nunca se llama explícitamente) puede tener cualquiera hay una definición o una definición única. En cualquier caso, múltiples definiciones para una función no-inline hace que el programa mal formada.

Por lo menos, estoy seguro de que es la intención. Pero usted puede estar en un agujero en la redacción, ya que una lectura muy literal no dice en ninguna parte que las múltiples definiciones diferentes de la misma función sin usar en diferentes unidades de traducción es mal formada.

// 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;
}

Esto está relacionado, pero fuera de tema: desde las citas parece que hay un agujero en el bien estándar: también debería decir que se utiliza un destructor virtual puro, y, que debe ser definida; al menos si existen cualesquiera objetos de clase derivados que son destruidos o si se define un destructor de los mismos, ya que el destructor clase derivada debe llamar al destructor base, implícitamente lo hace con la sintaxis cualificado :: ID. La definición de tales destructores suele ser trivial pero no puede ser elidido y no se puede generar.

[class.abstract]: "Una función virtual pura tiene por qué ser definido sólo si se llama con, o como si con (12.4), la sintaxis calificado-id (5,1)."

Su A::f es llamado por B::f, así que debe haber una definición única de A::f.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top