2017-04-13 6 views
2

L'idée est la suivante. J'ai une bibliothèque version 1 avec une classe qui se présente comme suit:C++ Héritage et bibliothèques dynamiques

class MY_EXPORT MyClass 
{ 
public: 
    virtual void myMethod(int p1); 
} 

Dans la version 2, la classe a été modifiée à ceci:

class MY_EXPORT MyClass 
{ 
public: 
    virtual void myMethod(int p1); 
    virtual void myMethod2(int p1, int p2); 
} 

//implementation of myMethod2 in cpp file 
void MyClass::myMethod2(int p1, int p2) 
{ 
    myMethod(p1); 
    //... 
} 

Maintenant, imaginez un utilisateur compilé againts version 1 de la bibliothèque et étendu MyClass en remplaçant myMethod. Maintenant, il met à jour la bibliothèque à la version 2, sans recompilation. Supposons en outre que l'éditeur de liens dynamiques trouve toujours la bibliothèque avec succès et la charge.

La question est, si j'appelle la méthode instance->myMethod2(1, 2); quelque part dans la bibliothèque, cela fonctionnera-t-il, ou l'application plantage? Dans les deux cas, la classe n'a pas de membres et est donc de la même taille.

+0

Puisque la classe héritée ne connaît pas l'interface modifiée, elle n'aura aucune information à son sujet dans sa table virtuelle. Cela conduira à un * comportement indéfini *. En bref: Si l'interface change, les applications en fonction de ces interfaces doivent être recompilées. –

Répondre

2

Je ne pense pas qu'il soit utile de deviner si cette application va tomber en panne ou non, le comportement est indéfini. L'application doit être recompilée, car il y avait un changement ABI dans la bibliothèque. Lorsque la bibliothèque appelle instance->myMethod2(1, 2);, elle doit passer par la table virtuelle créée dans le code de l'application en supposant qu'il n'existe qu'une seule méthode virtuelle: myMethod. À partir de ce moment, vous obtenez un comportement indéfini. En bref, vous devez recompiler votre application lorsque la bibliothèque ABI change.

+1

L'écrasement est en fait préférable car à ce stade, il n'y a pas d'ambiguïté, vous * savez * que vous avez un comportement indéfini. –

+0

@MarkRansom oui, il est proféré mais il pourrait y avoir un cas où il fonctionne silencieusement et fait quelque chose de mal à la place ou même fait exactement ce qui était attendu. – Pavel

1

KDE C++ ABI guidelines d'interdire spécifiquement un tel changement. Les tables virtuelles de classes dérivées ne contiendront pas d'adresses pour les nouvelles méthodes et les appels virtuels de ces méthodes sur les objets des classes dérivées se bloqueront.

0

En modifiant la définition de la classe sans la recompiler, vous avez enfreint la One Definition Rule. L'utilisateur qui n'a pas recompilé utilise l'ancienne définition, tandis que votre bibliothèque utilise la nouvelle définition. Cela entraîne un comportement indéfini.

Pour voir comment cela pourrait se manifester, considérons l'implémentation typique des fonctions virtuelles qui utilise une VTable pour répartir les appels de fonction. L'utilisateur de bibliothèque a dérivé une classe et cette classe dérivée n'a qu'une seule fonction dans la VTable. Si un pointeur ou une référence à cette classe est passé dans la bibliothèque et que la bibliothèque tente d'appeler la deuxième fonction, elle tentera d'accéder à une entrée VTable qui n'existe pas. Cela entraînera presque toujours un crash, bien que rien ne soit garanti quand il s'agit d'un comportement indéfini.