簡體   English   中英

為什么static_cast需要指針或引用?

[英]Why does static_cast require pointers or references?

最近,我不得不使用static_cast將父類強制轉換為子類,因為我知道對象實例就是該子類。 我基於if條件知道這一點。

像這樣:

parent* foo;
child* bar;
if(foo is instance of child class)
   bar = static_cast<child*>(foo)

我的問題是:為什么static_cast總是需要指針? 當我嘗試使用非指針變量時,這不起作用。 原始數據類型似乎是一個例外。

這是因為每個指針都可以轉換為void *嗎? 那是static_cast的工作方式嗎?

編輯:我忘了提及它與引用一起使用。 因此,當前提出的問題是錯誤的。 將問題重新定義為“為什么static_cast為什么需要指針或引用?”

為什么static_cast總是需要指針?

運算符static_cast不需要指針,也不需要引用。

C ++標准n3337§5.2.9 / 4:

否則, 如果聲明T t(e) ,則可以使用static_cast<T>(e)形式的static_cast<T>(e)將表達式e顯式轉換為T類型。 對於某些發明的臨時變量t (8.5), 其格式正確 這種顯式轉換的效果與執行聲明和初始化,然后將臨時變量用作轉換結果的效果相同。 當且僅當初始化將其用作glvalue時,才將表達式e用作glvalue。

parent* foo;
child* bar;
if(foo is instance of child class)
   bar = static_cast<child*>(foo)

當我嘗試使用非指針變量時,這不起作用。

例如? 您如何嘗試的? 如果你的意思是

child c;
parent p = static_cast<parent>( c);

然后這稱為切片 ,這意味着p將僅從c中獲取來自父類的數據(由於父子添加到派生的父數據中,父類的對象又如何接收子部分?)。

原因是:否,它可以是指針或引用。 這與以下問題有關:

 struct Base
 {

 };


 struct Derived : public Base
 {
   int A;
 };

 //sizeof(Base)==0
 //sizeof(Derived)==4
 Base B;
 Derived X;
 X.A = 10;
 B=X;//what happens to Derived::A? There is no space to put it. This is called slicing.

基本上,您不能在不冒切片風險的情況下,通過派生類對基類進行實例化。 但是引用/指針是另一回事。 在這種情況下,您只是在解釋如何解釋所指向的內存。 在這種情況下,靜態投射實際上不執行任何操作! 由於C ++類的布局方式(有意地),從基類繼承的所有內容都具有從0偏移量到sizeof(Base)的相同內存布局。 只有在那之后,您才添加派生的東西。

為什么static_cast總是需要指針?

好吧,並非總是如此。 如您所指出的,以下是可能的:

int i = static_cast<int>(3.14);

static_cast也可以用於在引用之間進行轉換,就像使用指針一樣。

但是,您必須考慮以下因素:在兩種類型之間進行轉換時,您可能會丟失信息。 假設您有一個Animal類,另一個是Dog類,它恰好繼承自它。 這是什么意思?

Dog d;
Animal a = static_cast<Animal>(d);

您是用Dog創建Animal的,但是Dog的特定信息將被丟棄。 這稱為切片

指針之間的轉換通常只涉及重新解釋內存。 基礎對象保持不變。

本質上, static_cast<>總是創建帶有尖括號之間提供的類型的新內容。 考慮:

class base { int x; };
class derived: public base { int y; };

現在,以下代碼將無法編譯:

base *b;
derived *d = &static_cast<derived>(*b);   // wrong

原因很簡單:此代碼嘗試創建derived新實例,並將base傳遞給其構造函數。 如果derived有該構造函數,它將進行編譯。 例如:

class derived: public base
{
  int y;
  derived(const base &){}
};

但是現在您有了一個臨時目錄,該臨時目錄將立即被刪除。

顯然,您不想在這里創建新的derived實例,但是要到達派生實例,您的基礎就是其中的一部分。 在執行轉換時,您需要創建對derived的引用或指針,而不是它的全新實例。 以下將起作用:

derived d;
base *bp = &d;
base &br =  d;
derived &dr = static_cast<derived &>(br);
derived *dp = static_cast<derived *>(bp);

現在, drdp指向上面相同的d

暫無
暫無

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

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