Domanda

C++03 3.2.2 ... viene utilizzato un oggetto o una funzione non sovraccaricata se il suo nome compare in un'espressione potenzialmente valutata. Una funzione membro virtuale viene utilizzata se non è puro ...

E poi in 3.2.3 abbiamo: Ogni programma deve contenere esattamente un definizione di ogni funzione non inline o un oggetto che viene usata in quel programma; nessun diagnostico richiesto. La definizione può apparire in modo esplicito nel programma, si può trovare nella norma o una libreria definita dall'utente, o (se del caso) è definito in modo implicito (vedi 12.1, 12.4 e 12.8). Una funzione inline è definita in ogni unità di traduzione in cui viene utilizzato.

Lungo le linee sto leggendo: una funzione virtuale pura non viene utilizzato. L'ODR applica solo alle funzioni che vengono utilizzati. Questo non implica che la seguente sarebbe legale? Sto indovinando la risposta è no, non è così, ma poi non riesco a capire il perché.

//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();
}
È stato utile?

Soluzione

I due clausole non si escludono a vicenda. Che una funzione virtuale viene utilizzata se non è pura, non significa che il viceversa detiene. Se una funzione virtuale è puro non significa che sia necessariamente non utilizzata. Può ancora essere utilizzato "se il suo nome appare in un'espressione potenzialmente valutata", come nel tuo esempio:. A::f();

Altri suggerimenti

Questo codice viola ODR. A :: f è definito più volte. Quindi ha UB.

Definizioni multiple attraverso le unità di traduzione sono ammessi solo per il seguente secondo $ 3,2 / 5

  

Non ci può essere più di una definizione   di un tipo di classe (clausola 9),   tipo di enumerazione (7.2), in linea   funzione con linkage esterno   (7.1.2), modello di classe (clausola 14),   modello di funzione non statici (14.5.5),   membro di dati static di una classe template   (14.5.1.3), funzione membro di una classe   modello (14.5.1.1), o un modello   specializzazione per cui alcuni template   parametri non sono specificati (14,7,   14.5.4) in un programma a condizione che ogni definizione appare in un diverso   unità di traduzione, e purché il   definizioni soddisfare la seguente   requisiti.

Come @Charles Bailey ha sottolineato, il tuo A::f viene infatti utilizzato anche se è pura virtuale. Ma non è questo il punto principale.

Non è preciso che la Regola Una definizione non si applica alle funzioni che non vengono utilizzati. Abbiamo:

  

3.2p1 Nessuna unità traduzione dovrà contenere più di una definizione di qualsiasi variabile, funzione, tipo di classe, tipo di enumerazione o modello.

     

3.2p3 programma Ogni dovrà contenere esattamente una definizione di ogni funzione non inline o un oggetto che viene usata in quel programma; nessun diagnostico richiesto.

Insieme, questi requisiti sembrano implicare che una funzione utilizzati devono avere esattamente una definizione, e una funzione non utilizzata (tra cui una funzione virtuale pura che non viene mai chiamato in modo esplicito) possono avere sia una definizione o una definizione unica. In entrambi i casi, le definizioni multiple per una funzione non inline rende il programma mal formato.

Almeno, io sono certo che è l'intento. Ma si può essere a un buco nel fraseggio, dal momento che una lettura molto letterale non dice da nessuna parte che più definizioni diverse della stessa funzione non utilizzata in diverse unità di traduzione è mal formate.

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

Questo è legato, ma off-topic: dalle citazioni sembra che ci sia un buco nel bene standard: si deve anche dire che un distruttore virtuale pura viene utilizzato, e, che deve essere definita; almeno se esistono oggetti classe derivata che vengono distrutti o se si definisce un distruttore di tale, dal momento che il distruttore classe derivata deve chiamare il distruttore base, implicitamente lo fa con la sintassi qualificato :: id. La definizione di tali distruttori di solito è banale, ma non può essere tralasciata e non può essere generato.

[class.abstract]: "Una funzione virtuale pura deve essere definito solo se chiamato con, o come se con (12.4), la sintassi qualificata-id (5.1)."

Il A::f è chiamato da B::f, quindi ci deve essere una definizione unica di A::f.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top