例如,建议总是从map<int,void*>hold
哪里存储指针,以后通过 static_cast 将其转换回来是否安全?void*
classA
classA* ptr = static_cast<classA*>( holditerator->second );
使用的原因void*
是因为hold
它是在某些不知道是什么的 cpp 文件使用的标头上定义的类的成员classA
。我必须classA
在这些 cpp 文件中包含定义的标题,这有很多原因无法完成。
是的,static_cast
在这种情况下没问题,而且使用正确。
我不得不问为什么你不classA*
首先存储指针。如果要将派生类指针放入其中,请注意,在将派生类指针放入映射classA*
之前,您需要向上转换/向上转换(隐式或显式)派生类指针。
但是即使您将派生类指针也放入映射中,基类指针就足够了,因为派生类指针可以隐式转换为基类指针。
使用 void* 的原因是因为 hold 是在某些不知道 classA 是什么的 cpp 文件使用的标头上定义的类的成员。
这可能是防止分层违规的正当理由。
我必须在这些 cpp 文件中包含 classA 定义的标题,这有很多原因无法完成。
在您的情况下,这很可能没有必要。前向声明就足够了。如果标头知道要放入地图中的内容,但只是想避免包含其他标头,那么这就是要走的路。
正如约翰内斯解释的那样,static_cast
没关系。另一种防止依赖ClassA
于 cpp 文件的技术是使用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() { }
仅仅因为地图的用户不应该知道实际类型而在标题中写入 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 () { }
};