2017-08-29 7 views
2

J'essaie d'implémenter une hiérarchie de classes CRTP. Je suis intéressé par la classe de base pour avoir accès à l'élément de données d'une classe dérivée de la chaîne:Pourquoi la hiérarchie CRTP suivante ne compile-t-elle pas?

#include <iostream> 

template <class Derived> 
class A { 
public: 
    void showv() { 
     std::cout << static_cast<const Derived*>(this)->v << std::endl; 
    } 
}; 

template <class Derived> 
class B : public A<Derived> { 
    typedef A<Derived> base; 
    friend base; 
}; 

class fromA : public A<fromA> { 
    typedef A<fromA> base; 
    friend base; 
protected: 
    int v = 1; 
}; 

class fromB : public B<fromB> 
{ 
    typedef B<fromB> base; 
    friend base; 
protected: 
    int v = 2; 
}; 

int main() 
{ 
    // This runs ok 
    fromA derived_from_a; 
    derived_from_a.showv(); 

    // Why doesn't the following compile and complains about the protected member? 
    fromB derived_from_b; 
    derived_from_b.showv(); 

    return 0; 
} 

Demo

Bien que la première classe dérivée (fromA) compile et fonctionne comme prévu, le deuxième (fromB), qui dérive d'une classe dérivée de A, ne le fait pas.

  1. Quelle est la raison pour laquelle les déclarations d'amis ne sont pas acheminées?
  2. Des suggestions sur une solution de contournement?
+0

pourquoi ne pas créer de fonction virtuelle getV() et le remplacer dans chaque classe dérivée au lieu des jeux avec des amis? –

+0

'ami' de mon' ami' n'est pas mon ami en C++. – Jarod42

Répondre

4

La question est la suivante: l'ami de mon ami est pas mon ami.

Dans fromA vous avez

typedef A<fromA> base; 
friend base; 

Ce qui fait A<fromA> un ami et show peuvent accéder fromA « s membres protégés.

En fromB vous avez également

typedef B<fromB> base; 
friend base; 

Mais cela ne fait pas A un ami, il fait B votre ami. Même si A est un ami de B cela ne signifie pas qu'il est maintenant un ami de fromB ce qui est la raison pour laquelle vous ne pouvez pas accéder à vshow.

Une façon de résoudre ce problème est de faire typedef A<Derived> base; public ou protégé en B puis à fromB vous pouvez ajouter friend base::base; qui donnerait accès A.

+0

Cela fonctionne, merci! Pour une raison quelconque, je pensais que 'base' enchaînait son résultat jusqu'à' fromB'. –