为什么摘要 class 不允许协方差?
Why is covariance not allowed with an abstract class?
class GameObject {
public:
virtual ~GameObject() {}
};
class Player: public GameObject {};
struct IGameController {
virtual GameObject* GetPlayer() = 0;
};
class CameraOnlyController : public IGameController {
public:
GameObject* GetPlayer() override { return nullptr; }
};
class PlayerController : public IGameController {
public:
PlayerController() { player = new Player(); }
~PlayerController() { delete player; }
Player* GetPlayer() override { return player; }
private:
Player* player;
};
int main() {
IGameController* playerController = new PlayerController();
Player* player = playerController->GetPlayer(); // error: a value of type "GameObject *" cannot be used to initialize an entity of type "Player *"
delete playerController;
}
如果我专门将控制器接口更改为 PlayerController,它确实可以编译
PlayerController* playerController = new PlayerController();
我知道 playerController 稍后可以像这样指向 CameraOnlyController
playerController = new CameraOnlyController();
但由于在 Player* 播放器初始化时它没有,为什么要阻止它?
是不是编译器试图强制执行类型安全,我假设它知道 playerController 当时已分配给 new PlayerController(),但这种假设是错误的?
IGameController* playerController = new PlayerController();
playerController
属于 IGameController*
.
类型
C++ 编译器类型检查 不会 记住关于 playerController
的任何其他内容。它忘记了它是由指向 PlayerController
.
的指针构造的事实
Player* player = playerController->GetPlayer();
所以这里它获取允许知道的信息,即 playerController
是一个 IGameController*
,并声明存在类型不匹配。
如果你想让编译器知道更多playerController
的类型,你必须自己改变playerController
的类型。 C++ 编译器不会自动将 playerController
的类型扩展为它在确定代码行的含义时可以知道的所有内容。
同时,C++编译器可以自由遵循as-if规则,对playerController
的类型进行去虚拟化。但他们可能只会这样做 ,因为如果 他们没有这样做(例如,使您的代码更快)。
存在允许对给定变量进行更广泛类型推导的编程语言。 C++ 不是其中之一。
你可以这样做:
auto* playerController = new PlayerController();
auto* player = playerController->GetPlayer();
delete playerController;
在这种情况下,将使用各种变量的确切类型,或者
auto* playerController = new PlayerController();
Player* player = playerController->GetPlayer();
delete playerController;
验证 player
是您想要的类型。
class GameObject {
public:
virtual ~GameObject() {}
};
class Player: public GameObject {};
struct IGameController {
virtual GameObject* GetPlayer() = 0;
};
class CameraOnlyController : public IGameController {
public:
GameObject* GetPlayer() override { return nullptr; }
};
class PlayerController : public IGameController {
public:
PlayerController() { player = new Player(); }
~PlayerController() { delete player; }
Player* GetPlayer() override { return player; }
private:
Player* player;
};
int main() {
IGameController* playerController = new PlayerController();
Player* player = playerController->GetPlayer(); // error: a value of type "GameObject *" cannot be used to initialize an entity of type "Player *"
delete playerController;
}
如果我专门将控制器接口更改为 PlayerController,它确实可以编译
PlayerController* playerController = new PlayerController();
我知道 playerController 稍后可以像这样指向 CameraOnlyController
playerController = new CameraOnlyController();
但由于在 Player* 播放器初始化时它没有,为什么要阻止它? 是不是编译器试图强制执行类型安全,我假设它知道 playerController 当时已分配给 new PlayerController(),但这种假设是错误的?
IGameController* playerController = new PlayerController();
playerController
属于 IGameController*
.
C++ 编译器类型检查 不会 记住关于 playerController
的任何其他内容。它忘记了它是由指向 PlayerController
.
Player* player = playerController->GetPlayer();
所以这里它获取允许知道的信息,即 playerController
是一个 IGameController*
,并声明存在类型不匹配。
如果你想让编译器知道更多playerController
的类型,你必须自己改变playerController
的类型。 C++ 编译器不会自动将 playerController
的类型扩展为它在确定代码行的含义时可以知道的所有内容。
同时,C++编译器可以自由遵循as-if规则,对playerController
的类型进行去虚拟化。但他们可能只会这样做 ,因为如果 他们没有这样做(例如,使您的代码更快)。
存在允许对给定变量进行更广泛类型推导的编程语言。 C++ 不是其中之一。
你可以这样做:
auto* playerController = new PlayerController();
auto* player = playerController->GetPlayer();
delete playerController;
在这种情况下,将使用各种变量的确切类型,或者
auto* playerController = new PlayerController();
Player* player = playerController->GetPlayer();
delete playerController;
验证 player
是您想要的类型。