铸造的原理是什么?

时间:2010-10-14 07:05:02

标签: c++ c casting

引自here

CMediaType mymt;

AM_MEDIA_TYPE pmt = (AM_MEDIA_TYPE*)&mymt;
  1. 为什么CMediaType对象可以投放到AM_MEDIA_TYPE
  2. c?
  3. 中是否提供此功能

    更新

    有人可以认真回答cast subclasses to their base classes背后的原则是什么,我可以反过来做吗?

    UPDATE2

    AM_MEDIA_TYPE/CMediaType施放

    GetMediaType(4, &m_mt);
    
    HRESULT GetMediaType(int iPosition, CMediaType *pmt)
    {
       ...
    
    HRESULT STDMETHODCALLTYPE SetFormat(AM_MEDIA_TYPE *pmt)
    {
        m_mt = *pmt;
        ...
    

5 个答案:

答案 0 :(得分:3)

在这种特殊情况下,CMediaType直接扩展AM_MEDIA_TYPE,因此演员阵容可以正常使用。 (你在谈论DirectShow类,是吗?)你总是可以安全地将子类转换为它们的基类,这就是为什么它可以工作。

这是一个带继承的简单类结构:

public class Animal {

    public abstract String makeSound();

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

}

public class Lion extends Animal {

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

     public void yawn() {
        ...
     }

}

你可以像这样实例化一只狮子,然后安全地将它投射到动物身上:

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

通过扩展Animal(或继承自Animal,因为它也被称为),Lion类声明它也是动物(它们具有is-a-relationship)因此,将狮子投射到动物并假设它具有Animal类中定义的所有属性和方法是安全的。

但是,将基类转换为子类通常不起作用:

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

这不行,因为不是每只动物都是狮子。根据语言的不同,您将在运行时获得类型转换错误或未定义的行为。

有一个例外:如果您确定您拥有的对象属于特定子类,则无论如何都可以执行转换。因此,如果动物实际上是Lion,那么这个工作就可以了:

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

大多数语言在运行时提供类型检查(“这只动物是狮子吗?”),我不知道C ++会有什么样子,所以另一个Java-ish例子:

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

答案 1 :(得分:2)

当你想以统一的方式访问一组派生实例时,通常会进行向上转换(从子到基础)(例如,你正在构建一个Animal实例列表,但你有Lion,Cow和Cat的实例)。如果您只需要通过Animal界面访问实例,那就没问题了。您可以在upcasted实例上调用Animal方法。

当你得到的是一堆Animal实例时,情况恰恰相反,但你必须只对具有特定类型的子集进行操作。这被称为向下转换,我读到了一种普遍倾向于皱眉,但在某些情况下它只是起作用。您使用dynamic_cast执行安全预测。如果对象不是您请求的实例,则返回null(如果使用指针,则会引发异常)。

在C中你没有课程。使用强制转换,您只需告诉编译器重新解释内存中字节数组的内容。我在GTK看到它做了很多。

这是C中的一个例子。重要提示:这是丑陋的C.我的C比1870卡车更生气,而且我很匆忙。这段代码中有很多注意事项。

#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);
}

当你转换为struct b *时,你用a_ptr用新的“vision”覆盖你之前引用的内存区域。通过b,您无法访问another_string,也无法访问a_third_string。

答案 2 :(得分:1)

C 没有继承的概念,它没有基类和子类。 这个概念仅存在于 C ++ 和大多数其他面向对象的语言,如C#或Java。

原则很简单。如果您的课程DogCat都来自Mammal。 如果Dog和Cat是Mammal的子类,那么它们总是Mammals,因此总是可以转换为Mammal

另一种方式并非如此简单。如果您将Cat投射到Mammal,则可以稍后投射回Cat。但是您无法将其强制转换为Dog,因为它仍然是Cat,尽管您可以通过强制转换将其存储到Mammal类型的变量中。

答案 3 :(得分:1)

您要问的是两个不同的功能:向上转换和类型转换。这两者在C ++中是截然不同的,因为你不需要进行类型转换以进行向上转换。向上转换是指将后代类的实例视为基类的实例;这背后的原则是Liskov substitution principle。类型转换涉及重新解释类型或在C ++中转换类型。有typecasting in C++种不同的种类,每种都有typecasting operators {static_castdynamic_castreinterpret_castconst_cast,C风格的广告。类型转换允许更一般的替换,并且不遵循违反它们的原则,这就是使用转换的C和C ++程序不是类型安全的原因。

答案 4 :(得分:0)

  

为什么CMediaType对象可以转换为AM_MEDIA_TYPE

这是一个设计决定。你不能把所有东西都扔给其他一切,你绝对是don't want to。此外,虽然您可以从base-to-derived或derived-to-base转换对象,但如果类定义了转换运算符,则可以在不相关的类之间进行转换。

我怀疑示例代码会创建一个CMediaType对象以利用RAII。但是调用的函数不会使用CMediaType,因此对象将转换为AM_MEDIA_TYPE

  

c中有这样的功能吗?

C中有强制转换,但系统不同。无法定义转换运算符,并且没有基类或派生类的语言概念。您可以编写接受一种类型对象并返回另一种对象的函数。您可能对GTK+ object model感兴趣,这是在C。

中实现的
  

将子类转换为基类的原理是什么,我可以反过来做吗?

示例代码使用C样式转换。我强烈反对在C ++代码中。 static_castdynamic_castconst_castreinterpret_cast都做了不同的事情,区分它们非常有用。

由于C中没有类型层次结构,因此没有向下转发或向上转发

所以,回答你对C ++的问题:从派生到基类的转换总是安全的。你甚至不必写演员:

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

回归不一定是安全的,所以你必须编写演员表并创建dynamic_cast,这样你就知道演员是否真的成功了:

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

同样,C没有dynamic_cast之类的东西,因为C没有类型层次结构。你可以使用C风格的演员表,但C风格的演员阵容无法报告“对不起,没有办法在这些对象之间施放。”您想要知道对象何时不相关,为此您需要使用dynamic_cast