![](/img/trans.png)
[英]When is a `static_cast<Base*>(static_cast<void*>(derived))` from a pointer to a derived class valid?
[英]static_cast from base class pointer to derived class pointer is invalid
我正在創建一個簡單的測試實體組件系統。 我有幾個派生類的基本Component
類。 然后,我有幾個將某些邏輯應用於這些組件的系統。
// Component.h
// ------------
class Component
{
public:
Component();
~Component();
}
// ControlComponent.h
// -------------------
#include <string>
#include "Component.h"
class ControlComponent : public Component
{
public:
std::string input = ""; // store simple input instruction
ControlComponent();
~ControlComponent();
};
// ControlSystem.cpp
void ControlSystem::update(Entity* entity)
{
vector<Component*>* components = entity->getComponents();
for (Component* component : *components)
{
PositionComponent* pc = static_cast<PositionComponent*>(component);
ControlComponent* cc = static_cast<ControlComponent*>(component);
if (pc != nullptr && cc != nullptr)
{
std::cout << "Which direction would you like to go?" << std::endl;
std::string input;
std::cin >> input;
cc->input = input; // application breaks here
// Apply some logic...
}
}
}
當我從基本Component*
static_cast
到任何派生組件( PositionComponent*
或ControlComponent*
)並且兩個結果都不為nullptr
(即nullptr
成功),我得到了無效值,例如cc->input
無法讀取字符串等字符
我將實體工廠中的組件連接起來,如下所示:
void EntityFactory::wireUpPlayer(Entity* player)
{
player->addComponent(new HealthComponent());
player->addComponent(new ControlComponent());
player->addComponent(new PositionComponent());
}
並且addComponent的實現如下:
void Entity::addComponent(Component* component)
{
m_components.push_back(component);
}
這些組件顯示為具有有效的內存地址,因此我不確定問題出在哪里。
static_cast
在運行時不檢查有效性; 如果強制轉換已編譯,則它將在運行時假定轉換正常。 如果您不強制轉換為空指針,則static_cast
的結果將不會為空指針。 要獲得檢查的dynamic_cast
轉換,您需要dynamic_cast
而這又要求將指針轉換為指向多態類型,即具有至少一個虛函數的類型。 這意味着將Component
更改為至少具有一個虛擬功能。
當我從基本
Component*
static_cast
到任何派生組件(PositionComponent*
或ControlComponent*
)並且兩個結果都不為nullptr
(即nullptr
成功)...
從基類轉換為派生類時, static_cast
告訴編譯器:“相信我,我知道我在做什么。” 換句話說,如果它甚至可能合法,它將“成功”並返回non- nullptr
。 如果在運行時不合法,則嘗試使用一個類的實例就像是另一個類的實例那樣,您將獲得未定義的行為。
請改用dynamic_cast
。
正如Pete Becker和Josh Kelley所說,請使用dynamic_cast
並且我相信您還需要將至少一個函數設置為virtual
。 如果您不這樣做,則編譯器將不會記錄繼承,而且dynamic_cast
可能仍會返回nullptr
。 執行繼承時,建議將類析構函數設為虛擬。 當需要在派生類的析構函數中處置非托管資源並且您只有指向基類的指針時,這也是一種好習慣,只要只要析構函數是虛擬的,就將調用派生類的析構函數。 這里有一篇文章對此進行了解釋: 什么時候使用虛擬析構函數?
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.