Question

C++03 3.2.2 ... Un objet ou une fonction non-surcharge est utilisé si son nom apparaît de dans une expression potentiellement évaluée. Une fonction de membre virtuel est utilisé si ce n'est pas pur ...

Et puis plus tard dans 3.2.3 nous avons: Chaque programme contient exactement une définition de toutes les fonctions non-ligne ou un objet qui est utilisé dans ce programme; pas de diagnostic nécessaire. La définition peut apparaître explicitement dans le programme, il se trouve dans la norme ou une bibliothèque définie par l'utilisateur, ou (le cas échéant), il est implicitement défini (voir 12.1, 12.4 et 12.8). Une fonction en ligne doit être définie dans chaque unité de traduction dans lequel il est utilisé.

Le long des lignes je lis: une fonction virtuelle pure n'est pas utilisé. Le ODR applique uniquement aux fonctions qui sont utilisées. Ne signifie que ce qui suit serait légal? Je devine que la réponse est non, il n'a pas, mais je ne peux donc pas comprendre pourquoi.

//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();
}
Était-ce utile?

La solution

Les deux clauses ne sont pas mutuellement exclusives. Cette fonction virtuelle est utilisée si elle est pas pur, ne signifie pas que l'inverse est également. Si une fonction virtuelle est pure, il ne signifie pas nécessairement qu'il est pas utilisé. Il peut encore être utilisé « si son nom apparaît dans une expression potentiellement évaluée », comme dans votre exemple. A::f();

Autres conseils

Ce code constitue une violation ODR. A :: f est défini multiplier. Par conséquent, il a UB.

Les définitions multiples à travers les unités de traduction ne sont autorisées que pour les éléments suivants selon 3,2 / 5 $

  

Il peut y avoir plus d'une définition   d'un type de classe (clause 9),   type d'énumération (7.2), en ligne   fonction de liaison externe   (7.1.2), modèle de classe (clause 14),   modèle de fonction non statique (14.5.5),   membre de données statiques d'un modèle de classe   (14.5.1.3), la fonction de membre d'une classe   gabarit (14.5.1.1), ou d'un modèle   spécialisation pour laquelle un certain modèle   les paramètres ne sont pas spécifiés (14.7,   14.5.4) dans un programme à condition que chaque définition apparaît dans un autre   l'unité de traduction, et à condition que la   définitions répondre aux critères suivants   exigences.

Comme @Charles Bailey a souligné, votre A::f est en fait utilisé, même si elle est virtuelle pure. Mais qui est à côté du point principal.

Il est pas exact que la règle Une définition ne concerne pas les fonctions qui ne sont pas utilisées. Nous avons:

  

3.2p1 Aucune unité de traduction contient plus d'une définition d'une variable, fonction, type de classe, type d'énumération ou modèle.

     

3.2p3 programme Chaque contient exactement une définition de toutes les fonctions non-ligne ou un objet qui est utilisé dans ce programme; aucun diagnostic requis.

Ensemble, ces exigences semblent indiquer qu'une fonction utilisée doit avoir exactement une définition et une fonction non utilisée (y compris une fonction virtuelle pure qui est jamais appelé explicitement) peut avoir soit pas de définition ou d'une seule définition. Dans les deux cas, plusieurs définitions pour une fonction non inline rend mal formé le programme.

Au moins, je suis tout à fait certain que est l'intention. Mais vous pouvez être à un trou dans le phrasé, car une lecture très littérale dire ne nulle part que plusieurs définitions différentes de la même fonction inutilisée dans différentes unités de traduction est mal formé.

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

Ceci est lié, mais hors-sujet: des citations il semble qu'il y ait un trou dans le bien standard: il faut dire aussi un destructeur virtuel pur est utilisé, et qu'il doit être défini; au moins s'il existe des objets de classe dérivés qui sont détruits ou si un tel destructor de est définie, puisque la destructor classe dérivée doit appeler la destructor de base, implicitement il le fait avec la syntaxe qualifiée :: id. La définition de ces Destructeurs est généralement trivial, mais ne peut pas être éludée et ne peut être généré.

[class.abstract]: "Une fonction virtuelle pure doit être définie que si elle est appelée avec, ou comme si avec (12.4), la syntaxe id qualifié (5.1)".

Votre A::f est appelé par B::f, il doit y avoir une définition unique de A::f.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top