[英]What's the principle of type casting?
從這里引用:
CMediaType mymt;
AM_MEDIA_TYPE pmt = (AM_MEDIA_TYPE*)&mymt;
CMediaType
對象可以AM_MEDIA_TYPE
為AM_MEDIA_TYPE
? 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_cast
, dynamic_cast
, reinterpret_cast
, const_cast
,C樣式const_cast
)。 類型轉換允許更通用的替換,並且沒有遵循違反它們的原則,這就是為什么使用強制轉換的C和C ++程序類型不安全的原因。
為什么
CMediaType
對象可以AM_MEDIA_TYPE
為AM_MEDIA_TYPE
?
這是設計決定。 您不能將所有內容都投射到其他所有內容上,並且您絕對不想這么做 。 同樣,雖然可以從基類到派生對象或派生到基類強制轉換對象,但如果類定義了轉換運算符,則可以在不相關的類之間強制轉換。
我懷疑示例代碼創建了一個CMediaType
對象來利用RAII 。 但是調用的函數不采用CMediaType
,因此該對象被AM_MEDIA_TYPE
轉換為AM_MEDIA_TYPE
。
C中有這樣的功能嗎?
C中有強制轉換,但是系統不同。 沒有定義轉換運算符的方法,也沒有基類或派生類的語言概念。 您可以編寫采用一種類型的對象並返回另一種類型的對象的函數。 您可能對用C實現的GTK +對象模型感興趣。
將子類強制轉換為基類的原理是什么,我可以反過來嗎?
該示例代碼使用C樣式強制轉換。 我強烈不建議在C ++代碼中這樣做。 static_cast
, dynamic_cast
, const_cast
和reinterpret_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.