views:

147

answers:

6

Quoted from here:

CMediaType mymt;

AM_MEDIA_TYPE pmt = (AM_MEDIA_TYPE*)&mymt;
  1. Why can a CMediaType object be cast to AM_MEDIA_TYPE?
  2. Is such feature available in c?

UPDATE

Can someone answer it seriously what's the principle behind cast subclasses to their base classes, can I do it the other way around?

UPDATE2

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;
    ...
+3  A: 

In this particular case, CMediaType extends AM_MEDIA_TYPE directly, so the cast will work just fine. (You're talking about the DirectShow classes, are you?) You can always cast subclasses to their base classes safely, that's why it'll work.

Here's a simple class structure with inheritance:

public class Animal {

    public abstract String makeSound();

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

}

public class Lion extends Animal {

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

     public void yawn() {
        ...
     }

}

You could instantiate a lion like this and then cast it to an Animal safely:

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

By extending Animal (or inheriting from Animal, as it's also called), the Lion class states that it is also an animal (they have a is-a-relationship), therefore, it's safe to cast a lion to an animal and assume it has all the properties and methods defined in the Animal class.

Casting a base class to a subclass, however, will not usually work:

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

This can't work, as not every animal is a lion. Depending on the language, you'll either get type cast errors or just undefined behaviour at runtime.

There's an exception: If you know for certain the object you have is of a particular subclass, you can do the cast anyway. So in if animal in fact is a Lion, this'll work just fine:

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

Most languages offer type checks at runtime ("Is this animal a lion?"), I don't know how that would look in C++, though, so another Java-ish example:

if (animal instanceof Lion) {
    Lion lion = (Lion) animal; //safe
}
Henning
What's the principle behind `cast subclasses to their base classes`?
icurl
@icurl do you mean why the explicit `(Animal)` cast?
Earlz
Can I cast an animal to lion then? I'm see both `CMediaType/AM_MEDIA_TYPE` and `AM_MEDIA_TYPE/CMediaType` casting,so I don't understand.
icurl
@icurl: No, see my update.
Henning
The question was tagged with c++. This code looks like c#.
JoshD
It's hard to remember such behavior unless knowing the principles underneath. And,does it happen with `c` ?
icurl
Well, C does not actually have classes. I think you can cast structs, but my C/C++ is quite rusty, I don't know what would happen there. It'll probably just be undefined behaviour unless the structs are exactly compatible in the way they store information (i.e. have the same fields).
Henning
@JoshD - java..
pm100
@pm100: Ah, thanks. I just wanted to be sure the asker understood... just in case :)
JoshD
A: 

concering 2: yes, but Hennings answer applies there as well...

Philipp
+2  A: 

Upcasting (from sub to base) is commonly done when you want to access a set of derived instances in a uniform way (for example, you are building a list of Animal instances, but you have instances of Lion, Cow and Cat). If you need to access the instances just through the Animal interface, there's no problem. You can call Animal methods on upcasted instances.

The opposite happens when all you get is a bunch of Animal instances, but you have to operate only on the subset of them having a particular type. This is called downcasting, I read a general tendency to frown upon it, but in some cases it just works. You perform a safe downcasting with dynamic_cast. If the object is not of the instance you request, it returns null (if you are working with pointers, otherwise it raises an exception).

In C you don't have classes. With casting, you just tell the compiler to reinterpret the contents of the byte array you have in memory. I've seen it done a lot in GTK.

This is an example in C. IMPORTANT: this is ugly C. My C is rustier than a 1870 truck and I am in a hurry. There's plenty of don'ts in this 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);
}

When you cast to struct b *, you overlay the memory area you previously referred with a_ptr with the new "vision" through b. Via b, you cannot access another_string nor a_third_string.

Stefano Borini
But what I see doesn't use `dynamic_cast`,just `sub = *(pointer_to_base)`.
icurl
Can you elaborate what'll happen what if I cast structure A to structure B in c?
icurl
in C++, casting that way is the same as a `static_cast`, as far as I remember
Stefano Borini
A: 

Why can a CMediaType object be cast to AM_MEDIA_TYPE?

This is a design decision. You can't cast everything to everything else, and you definitely don't want to. Also, while you can cast objects from base-to-derived or derived-to-base, you can cast between unrelated classes if the classes define conversion operators.

I suspect that the sample code creates a CMediaType object to take advantage of RAII. But the function called doesn't take a CMediaType, so the object is cast to an AM_MEDIA_TYPE.

Is such feature available in c?

There are casts in C, but the system is different. There is no way to define conversion operators, and there is no language concept of base or derived classes. You can write functions that take objects of one type and return objects of another. You may be interested in the GTK+ object model, which is implemented in C.

what's the principle behind cast[ing] subclasses to their base classes, can I do it the other way around?

The sample code uses a C-style cast. I highly discourage that in C++ code. static_cast, dynamic_cast, const_cast and reinterpret_cast all do different things, and it is very useful to distinguish between them.

Since there are no type hierarchies in C there is no downcasting or upcasting.

So, answering your question for C++: casting from a derived to a base class is always safe. You don't even have to write the cast:

// 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 back is not necessarily safe, so you must write the cast and dynamic_cast was created so you know if the cast actually succeeded:

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
...

Again, C doesn't have anything like dynamic_cast because C doesn't have type hierarchies. You can use a C-style cast, but there is no way for a C-style cast to report "sorry, there is no way to cast between those objects." You want to know when objects aren't related, and for that you need to use dynamic_cast.

Max Lybbert
But the downcasting in my sample didn't use `dynamic_cast`
icurl
I've corrected, clarified, and edited the answer.
Max Lybbert
+1  A: 

C has no concept of inheritance, it has no base and sub classes. This concept exist only in C++ and most other object oriented languages like C# or Java.

The principle is simple. If you have a class Dog and Cat which both derive from Mammal. If Dog and Cat are subclasses of Mammal, thus they are always Mammals, and therefore can alway be cast into a Mammal.

The other way around is not so simple. If you cast a Cat to a Mammal you can then later cast is back into Cat. But you cannot cast it to Dog, because it is still a Cat, although you may have stored it into a variable of type Mammal by casting it.

codymanix
+1  A: 

You're asking about two different features: upcasting and typecasting. The two are distinct in C++, since you don't need typecasting to upcast. Upcasting is when you treat an instance of a descendent class as an instance of a base class; the principle behind this is the Liskov substitution principle. Typecasting involves reinterpreting the type or converting between types in C++. There are different kinds of typecasting in C++, each with different typecasting operators (static_cast, dynamic_cast, reinterpret_cast, const_cast, C-style cast). Typecasting allows for more general substitutions, and doesn't so much follow a principle as violate them, which is why C and C++ programs that use casting aren't type safe.

outis