Un pointeur de classe de base peut pointer sur un objet de classe dérivé. Pourquoi l'inverse n'est-il pas vrai sans casting? Logiquement, une classe de base n'aurait pas assez d'informations sur la classe dérivée, mais une classe dérivée devrait également avoir les informations de la classe de base . Il manque quelques bases ici.
Si je vous dis que j'ai un chien, vous pouvez supposer que j'ai un animal de compagnie.
Si je vous dis que j'ai un animal de compagnie, vous ne savez pas si cet animal est un chien, ce pourrait être un chat ou peut-être même une girafe. Sans connaître certaines informations supplémentaires, vous ne pouvez pas présumer que j'ai un chien.
de même, un objet dérivé est un objet de classe de base (comme c'est une sous-classe), il peut donc être pointé par un pointeur de classe de base. Toutefois, un objet de classe de base n'est pas un objet de classe dérivé et ne peut donc pas être affecté à un pointeur de classe dérivé.
(Le craquement que vous allez entendre maintenant est l'analogie qui s'étire)
Supposons que vous vouliez maintenant m'acheter un cadeau pour mon animal de compagnie.
Dans le premier scénario, vous savez que c'est un chien, vous pouvez m'acheter une laisse, tout le monde est heureux.
Dans le second scénario, je ne vous ai pas dit quel était mon animal de compagnie, alors si vous voulez m'acheter un cadeau, vous devez tout de même connaître des informations que je ne vous ai pas dites (ou devinez), vous m'achetez une il s'avère que j'ai vraiment eu un chien, tout le monde est heureux.
Cependant, si j'avais réellement un chat, nous savons maintenant que vous avez fait une mauvaise hypothèse et que vous avez un chat malheureux en laisse (erreur d'exécution).
Nous avons deux objets.
class A {
int a;
};
class B : A {
int b;
};
Allouer une instance de B
. Nous pouvons nous connecter avec cela en tant que A*
ou B*
.
Allouer une instance de A
. Si nous devions le convertir en B*
, un espace devrait-il être attribué au membre b
?
Euh, parce que la classe de base n'est pas une classe dérivée.
Lorsque vous avez un pointeur valide sur un type, vous dites que l'objet pointé aura certaines données à certains emplacements afin que nous puissions les trouver. Si vous avez un pointeur sur un objet dérivé, vous garantissez que l'objet pointé contient tous les membres de données de Derived, mais lorsque vous pointez sur une base, il n'a en fait pas cela et Bad Things Happen ™.
Toutefois, Derived est assuré d'avoir tous les membres de données de base aux mêmes emplacements. C'est pourquoi un pointeur sur Base peut en réalité pointer sur Derived.
Ceci est valable, car un tigre est un animal:
Animal * pAnimal = new Tiger();
Ce n'est pas valide, car il n'est pas vrai que l'objet soit un poison Dart Frog.
PoisonDartFrog * pPoisonDartFrog = new GenericFrog();
Parce qu'une classe dérivée inclut tout ce qui est dans la classe de base. Mais une classe de base n'inclut pas tout ce qui se trouve dans la classe dérivée.
Il n'est pas recommandé de transtyper une classe de base en classe dérivée: qu'arrivera-t-il si vous essayez d'accéder à des membres qui ne font pas partie de la classe de base?
C++ étant un langage typé de manière statique, autoriser des conversions implicites de la base vers le système dérivé briserait le système de types. Bjarne Stroustrup ne souhaitait aucune erreur d'exécution "message non compris".
La réponse courte
class A{
public:
method1();
};
class B: public A{
public:
method2();
};
int main(){
// Case 1
A* ptr_base = new B();
// Here I can call all the methods in A by ptr_base even though it is assigned B ...
// ... because B is derived from A and has all the information about methods of A
// Case 2
B* ptr_derived = new A(); // this will cause error
// Now here ptr_derived is assigned information of A ...
// ... So with this information can I call (*ptr_derived).method2(); ?...
// ... the answer is No because A does not have information of method2() ...;
// ... thus this declaration loses its meaning and hence error.
return 0;
}
class Base
{
public:
int a;
}
class Derived : public Base
{
public:
float b;
}
Base * pBase = new Base();
pBase->a = 7; // setting the value of a in the base
// make a pDerived that points to the SAME DATA as pBase
Derived * pDerived = pBase;
pDerived->a = 5; // this would be okay, base has a public member 'a'
pDerived->b = 0.2f; // error pBase has no data member b and pDerived
// points to the SAME DATA as pBase
Car un pointeur de classe de base peut pointer sur une instance de la classe de base ou sur tout type dérivé. Un pointeur dérivé ne peut pointer que sur ce type dérivé ou sur l'une de ses sous-classes.
struct Base {};
struct Derived : Base {};
struct Derived2 : Base {};
Base* p = new Derived(); //Fine, Derived inherits from Base
Derived* d = new Base(); //Not fine, Base is not an instance of nor derived from Derived.
Derived* d2 = new Derived2(); // Also not fine, Derived2 derives from Base, but is not related to Derived.
En ce qui concerne le pourquoi: En général, le pointeur de base est plus général que le pointeur dérivé. En tant que tel, il en sait moins sur le type hérité. Un pointeur dérivé ne peut pas être affecté à un type de base sans conversion, simplement parce qu'il ne peut pas dire si le pointeur de base est du type dérivé ou de l'un de ses enfants.
Si vous affectez une adresse d'un pointeur de classe de base à un pointeur de classe dérivée, vous pouvez éventuellement affecter un objet de classe de base à un pointeur de classe dérivée. Vous courez le risque d'accéder aux membres de la classe dérivée lorsque vous n'avez pas de classe dérivée. Alors que les méthodes de classe dérivées fonctionnent sur une classe de base, elles ne le feraient que si la méthode n'accédait pas aux données des membres de classe dérivés.
C'est un risque énorme.
Nous vous obligeons donc à faire un casting pour que vous ayez à reconnaître l'avertissement qui y est énoncé (vous pouvez commettre une erreur stupide, soyez prudent).
En général, un pointeur d'un type ne peut pas pointer sur un objet d'un type différent. Cependant, il existe une exception importante à cette règle qui concerne uniquement les classes dérivées . Dans cette situation, un pointeur de type BASE * peut pointer sur un objet de type Derived, c’est-à-dire qu'un pointeur de classe de base peut pointer sur un objet de classe dérivée mais l'inverse n'est pas vrai car l'objet de base n'est pas son objet de sous-classe.