簡體   English   中英

類型轉換的原理是什么?

[英]What's the principle of type casting?

這里引用:

CMediaType mymt;

AM_MEDIA_TYPE pmt = (AM_MEDIA_TYPE*)&mymt;
  1. 為什么CMediaType對象可以AM_MEDIA_TYPEAM_MEDIA_TYPE
  2. C中有這樣的功能嗎?

UPDATE

有人可以認真回答嗎? 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;
    ...

在這種情況下, CMediaType直接擴展AM_MEDIA_TYPE ,因此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風格的例子:

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

當您要以統一的方式訪問一組派生實例時(例如,您正在構建Animal實例列表,但是您有Lion,Cow和Cat實例),通常完成從子實例到基礎實例的上載。 如果您只需要通過Animal界面訪問實例,就沒有問題。 您可以在轉換后的實例上調用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);
}

當您強制轉換為結構b *時,您會將先前用a_ptr引用的存儲區與新的“ vision”至b覆蓋在一起。 通過b,您無法訪問another_string或a_third_string。

C沒有繼承的概念,沒有基類和子類。 這個概念僅存在於C ++和大多數其他面向對象的語言(如C#或Java)中。

原理很簡單。 如果您有一門“ Dog和“ Cat這兩種都來自Mammal的課程。 如果Dog和Cat是Mammal子類,那么它們始終是Mammals ,因此總是可以被鑄成Mammal

另一種方法不是那么簡單。 如果將Cat放到Mammal ,則可以稍后放回Cat 但是您不能將其強制轉換為Dog ,因為它仍然是Cat ,盡管您可能通過強制轉換將其存儲到了Mammal類型的變量中。

您要問兩個不同的功能:向上轉換和類型轉換。 兩者在C ++中是不同的,因為您不需要類型轉換就可以進行轉換。 向上轉換是將后代類的實例視為基類的實例時; 這背后的原理是Liskov替代原理 類型轉換涉及在C ++中重新解釋類型或在類型之間進行轉換。 C ++中有不同類型的類型轉換 ,每種類型轉換都有不同的類型轉換運算符static_castdynamic_castreinterpret_castconst_cast ,C樣式const_cast )。 類型轉換允許更通用的替換,並且沒有遵循違反它們的原則,這就是為什么使用強制轉換的C和C ++程序類型不安全的原因。

為什么CMediaType對象可以AM_MEDIA_TYPEAM_MEDIA_TYPE

這是設計決定。 您不能將所有內容都投射到其他所有內容上,並且您絕對不想這么做 同樣,雖然可以從基類到派生對象或派生到基類強制轉換對象,但如果類定義了轉換運算符,則可以在不相關的類之間強制轉換。

我懷疑示例代碼創建了一個CMediaType對象來利用RAII 但是調用的函數不采用CMediaType ,因此該對象被AM_MEDIA_TYPE轉換為AM_MEDIA_TYPE

C中有這樣的功能嗎?

C中有強制轉換,但是系統不同。 沒有定義轉換運算符的方法,也沒有基類或派生類的語言概念。 您可以編寫采用一種類型的對象並返回另一種類型的對象的函數。 您可能對用C實現的GTK +對象模型感興趣。

將子類強制轉換為基類的原理是什么,我可以反過來嗎?

該示例代碼使用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並創建了dynamic_cast ,以便您知道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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM