例如,建议map<int,void*>hold
其中void*
始终存储来自classA
的指针,以后通过static_cast将其强制转换是否安全?
classA* ptr = static_cast<classA*>( holditerator->second );
使用void*
的原因是因为hold
是在某些cpp文件使用的标头上定义的类的成员,这些文件不知道classA
是什么。我必须在这些cpp文件中包含classA
定义的标题,这是由于很多原因无法完成的。
答案 0 :(得分:13)
是的,static_cast
在这种情况下是正常的,并且正确使用。
我不得不问你为什么不首先存储classA*
指针。如果要将派生类指针放入其中,然后要注意,则需要在之前将派生类指针向上/上转换(隐式或显式)到classA*
你把它们放入地图。
但即使您将派生类指针放入映射中,基类指针也足够了,因为派生类指针可以隐式转换为基类指针。
使用void *的原因是因为hold是某些cpp文件使用的标头上的一个类的成员,这些文件不知道classA是什么。
这可能是防止分层违规的正当理由。
我必须在这些cpp文件中包含classA定义的标题,这是由于很多原因无法完成的。
在您的情况下,这很可能不是必需的。前瞻性声明就足够了。如果标题知道放入地图的内容,但只是想避免包含其他标题,那么这就是要走的路。
答案 1 :(得分:6)
正如约翰内斯所解释的那样,static_cast
还可以。另一种防止cpp文件中ClassA
依赖的技术是使用pimpl idiom。
// in header file
class classB {
public:
classB();
~classB();
private:
class impl;
unique_ptr<impl> pimpl;
};
// in implementation file
#include "classA.hpp"
class classB::impl
{
std::map<int, classA> hold; // hidden in implementation file
};
classB::classB() : pimpl{ new impl{ /*...*/ } } { }
classB::~classB() { }
答案 2 :(得分:2)
在标题中写入void *只是因为地图的用户不应该知道实际的类型是而不是一个好主意,因为你在代码中的所有地方都失去了类型安全性,包括在哪些地方了解ClassA。
考虑
第5点:插图(=模板模式)
而不是
class Containing {
private:
map<int,void*> myMap;
public:
void somePublicFunction () { // ...implementation }
};
你写了
// Containing.h
class Containing {
protected:
virtual void doSomething () = 0;
public:
static Containing* Create ();
void somePublicFunction () { doSomething (); }
virtual ~Containing () { }
};
// Containing.cc
#include ContainingImplementation.h
Containing* Containing::Create () { return new ContainingImplementation; }
// ContainingImplementation.h / cc
class ContainingImplementation : public Containing {
protected:
virtual void doSomething () { // ... }
private:
map<int,ClassA*> myMap;
public:
virtual ~ContainingImplementation () { }
};