2010-10-14 5 views
2

cité de here:Quel est le principe de la coulée de type?

CMediaType mymt; 

AM_MEDIA_TYPE pmt = (AM_MEDIA_TYPE*)&mymt; 
  1. Pourquoi un objet peut CMediaType être jeté à AM_MEDIA_TYPE?
  2. Une telle fonctionnalité est-elle disponible dans c?

MISE À JOUR

Quelqu'un peut-il répondre au sérieux ce qui est le principe cast subclasses to their base classes, je peux le faire dans l'autre sens?

MAJ2

AM_MEDIA_TYPE/CMediaType casting

GetMediaType(4, &m_mt); 

HRESULT GetMediaType(int iPosition, CMediaType *pmt) 
{ 
    ... 

HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt) 
{ 
    m_mt = *pmt; 
    ... 
+0

Bonjour, parlez-vous spécifiquement de C ou C++? Vous mentionnez C dans votre question mais étiqueté avec C++. – Earlz

+0

Les deux, en fait. – icurl

Répondre

3

Dans ce cas particulier, CMediaType étend AM_MEDIA_TYPE directement, de sorte que le casting fonctionnera très bien. (Vous parlez des classes DirectShow, êtes-vous?) Vous pouvez toujours lancer des sous-classes à leurs classes de base en toute sécurité, c'est pourquoi ça va marcher.

Voici une simple structure de classe avec l'héritage:

public class Animal { 

    public abstract String makeSound(); 

    public void move(...) { 
     ... 
    } 

} 

public class Lion extends Animal { 

    public String makeSound() { 
     return "GRRRRRR"; 
    } 

    public void yawn() { 
     ... 
    } 

} 

Vous pouvez instancier un lion comme celui-ci, puis le jeter à une sécurité animale:

Lion lion = new Lion(); 
Animal animal = (Animal) lion; //Perfectly legal 
animal.move(); 
animal.makeSound(); 

En étendant Animal (ou héritant de Animal , comme on l'appelle aussi), la classe Lion déclare que c'est aussi un animal (ils ont une relation is-a), donc, il est sûr de lancer un lion à un animal et de supposer qu'il a toutes les propriétés et méthodes définies dans la classe Animal.

casting une classe de base à une sous-classe, cependant, ne fonctionnera pas habituellement:

Animal animal = getAnimalFromSomeWhere(); 
Lion lion = (Lion) animal; 
lion.yawn(); 

Cela ne peut pas fonctionner, car pas tous les animaux est un lion. En fonction de la langue, vous obtiendrez des erreurs de type cast ou juste un comportement indéfini lors de l'exécution.

Il existe une exception: Si vous savez avec certitude que l'objet dont vous disposez appartient à une sous-classe particulière, vous pouvez quand même effectuer le cast. Donc, si l'animal est en fait un Lion, ça va très bien fonctionner:

Animal animal = getAnimalFromSomeWhere(); 
Lion lion = (Lion) animal; //works if animal is lion, fails otherwise 
lion.yawn(); 

La plupart des langues offrent des contrôles de type à l'exécution (« ? Est-ce cet animal un lion »), je ne sais pas comment cela pourrait regarder en C++, bien que, si un autre exemple Java-ish:

if (animal instanceof Lion) { 
    Lion lion = (Lion) animal; //safe 
} 
+0

Quel est le principe derrière 'les sous-classes de cast à leurs classes de base'? – icurl

+0

@icurl voulez-vous dire pourquoi le '' (Animal) 'explicite? – Earlz

+0

Puis-je lancer un animal à lion alors? Je vois à la fois les castings 'CMediaType/AM_MEDIA_TYPE' et 'AM_MEDIA_TYPE/CMediaType', donc je ne comprends pas. – icurl

2

transtypage ascendant (à partir de sous à la base) est généralement fait lorsque vous souhaitez accéder à un ensemble d'instances dérivées d'une manière uniforme (par exemple, vous êtes construire une liste d'instances d'Animal, mais vous avez des instances de Lion, Vache et Chat). Si vous avez besoin d'accéder aux instances via l'interface Animal, il n'y a pas de problème. Vous pouvez appeler des méthodes Animal sur des instances mises à jour.Le contraire se produit quand tout ce que vous obtenez est un tas d'instances d'animaux, mais vous devez opérer seulement sur le sous-ensemble d'entre eux ayant un type particulier. C'est ce qu'on appelle le downcasting, j'ai lu une tendance générale à désapprouver, mais dans certains cas cela fonctionne tout simplement. Vous effectuez une descente en toute sécurité avec dynamic_cast. Si l'objet n'est pas de l'instance que vous demandez, il renvoie null (si vous travaillez avec des pointeurs, sinon il déclenche une exception).

En C, vous n'avez pas de cours. Avec le cast, vous dites simplement au compilateur de réinterpréter le contenu du tableau d'octets que vous avez en mémoire. Je l'ai vu beaucoup fait dans GTK.

Ceci est un exemple en C. IMPORTANT: c'est moche C. Mon C est plus rusé qu'un camion de 1870 et je suis pressé. Il y a beaucoup de choses à ne pas faire dans ce code.

#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
struct a { 
    int an_int; 
    char a_string[8]; 
    char another_string[16]; 
    char a_third_string[16]; 
}; 

struct b { 
    int an_int; 
    char first_four[4]; 
    char last_four[4]; 
}; 

int main() { 
    struct a *a_ptr=NULL; 
    struct b *b_ptr=NULL; 

    a_ptr = malloc(sizeof(struct a)); 
    bzero(a_ptr, sizeof(struct a)); 

    a_ptr->an_int =10; 
    strncpy(a_ptr->a_string,"hello", 8); 
    a_ptr->a_string[strlen("hello")] = 0; 
    strncpy(a_ptr->another_string,"hello2", 16); 
    a_ptr->another_string[strlen("hello2")] = 0; 
    strncpy(a_ptr->a_third_string,"hello3", 16); 
    a_ptr->a_third_string[strlen("hello3")] = 0; 


    b_ptr = (struct b *)a_ptr; 

    printf("%n\n", b_ptr->an_int); 
    printf("%s\n", b_ptr->last_four); 
} 

Quand vous lancez struct b *, vous superposez la zone de mémoire dont vous avez parlé précédemment avec a_ptr avec la nouvelle « vision » à b. Via b, vous ne pouvez pas accéder à another_string ni à a_third_string.

+0

Mais ce que je vois n'utilise pas 'dynamic_cast', juste' sub = * (pointer_to_base) '. – icurl

+0

Pouvez-vous élaborer ce qui arrivera si je jette la structure A à la structure B dans c? – icurl

+0

en C++, le cast de cette façon est la même chose qu'un 'static_cast', autant que je me souvienne –

0

Pourquoi un objet peut CMediaType être jeté à AM_MEDIA_TYPE?

Ceci est une décision de conception. Vous ne pouvez pas tout jeter à tout le reste, et vous avez définitivement don't want to. En outre, si vous pouvez convertir des objets de base en base ou dérivés en base, vous pouvez effectuer des cast entre classes non liées si les classes définissent des opérateurs de conversion.

Je suspecte que l'exemple de code crée un objet CMediaType pour tirer parti de RAII. Mais la fonction appelée ne prend pas de CMediaType, donc l'objet est transtypé en AM_MEDIA_TYPE.

Une telle fonctionnalité est-elle disponible dans c?

Il existe des conversions en C, mais le système est différent. Il n'y a aucun moyen de définir les opérateurs de conversion, et il n'y a pas de concept de langage pour les classes de base ou dérivées. Vous pouvez écrire des fonctions qui prennent des objets d'un type et renvoient des objets d'un autre. Vous pouvez être intéressé par le GTK+ object model, qui est mis en œuvre en C.

ce qui est le principe cast [ant] les sous-classes à leurs classes de base, puis-je faire l'inverse?

L'exemple de code utilise un cast de style C. Je décourage fortement cela dans le code C++. Tous font des choses différentes, et il est très utile de les distinguer.

Comme il n'y a pas de hiérarchie de types dans C, il n'y a pas de downcasting ou de upcasting. Donc, répondant à votre question pour C++: la conversion d'une classe dérivée vers une classe de base est toujours sûre.Vous ne devez même pas écrire le casting:

// BTW, prefer smart pointers like boost::scoped_ptr 
Derived* foo = new Derived(); 
Base* bar = foo; 
// or you could write simply "Base* bar = new Derived()" 

casting retour est pas forcément en sécurité, vous devez donc écrire le casting et dynamic_cast a été créé afin de savoir si le casting effectivement réussi:

Base* foo = new Derived(); 
Derived* bar = dynamic_cast<Derived*>(foo); 
if (bar == NULL) { 
    // foo didn't point to a Derived or something derived from Derived 
    return; 
} 
// foo DID point to a Derived or something derived from Derived, access it through bar 
... 

Encore une fois, C n'a rien comme dynamic_cast parce que C n'a pas de hiérarchies de types. Vous pouvez utiliser un transtypage de style C, mais il est impossible pour un acteur de type C de signaler "Désolé, il n'existe aucun moyen de diffuser entre ces objets". Vous voulez pour savoir quand les objets ne sont pas liés, et pour cela vous devez utiliser dynamic_cast.

+0

Mais la descente dans mon échantillon n'a pas utilisé' dynamic_cast' – icurl

+0

J'ai corrigé, clarifié, et édité la réponse. –

1

C n'a pas de concept d'héritage, il n'a aucune base et sous-classes. Ce concept n'existe que dans C++ et la plupart des autres langages orientés objet comme C# ou Java.

Le principe est simple. Si vous avez une classe Dog et Cat qui dérivent tous les deux de Mammal. Si Dog et Cat sont des sous-classes de Mammal, elles sont donc toujours Mammals, et peuvent donc toujours être transformées en Mammal.

L'inverse n'est pas si simple. Si vous lancez un Cat vers un Mammal, vous pouvez ensuite le lancer plus tard dans Cat. Mais vous ne pouvez pas le convertir en Dog, car il s'agit toujours d'un Cat, bien que vous l'ayez stocké dans une variable de type Mammal en le castant.

1

Vous vous interrogez sur deux fonctionnalités différentes: le upcasting et le typecasting. Les deux sont distincts en C++, puisque vous n'avez pas besoin de typer pour monter. Upcasting est lorsque vous traitez une instance d'une classe descendante en tant qu'instance d'une classe de base; le principe derrière ceci est le Liskov substitution principle. Typecasting implique de réinterpréter le type ou de convertir entre les types en C++. Il existe différents types de typecasting in C++, chacun avec différents typecasting operators (static_cast, dynamic_cast, reinterpret_cast, const_cast, fonte de style C). Typecasting permet des substitutions plus générales, et ne suit pas un principe comme les violer, c'est pourquoi les programmes C et C++ qui utilisent le cast ne sont pas de type safe.