6

例如,建议总是从map<int,void*>hold哪里存储指针,以后通过 static_cast 将其转换回来是否安全?void*classA

classA* ptr = static_cast<classA*>( holditerator->second );

使用的原因void*是因为hold它是在某些不知道是什么的 cpp 文件使用的标头上定义的类的成员classA。我必须classA在这些 cpp 文件中包含定义的标题,这有很多原因无法完成。

4

3 回答 3

13

是的,static_cast在这种情况下没问题,而且使用正确。

我不得不问为什么你不classA*首先存储指针。如果要将派生类指针放入其中,请注意,在将派生类指针放入映射classA* 之前,您需要向上转换/向上转换(隐式或显式)派生类指针。

但是即使您将派生类指针也放入映射中,基类指针就足够了,因为派生类指针可以隐式转换为基类指针。

使用 void* 的原因是因为 hold 是在某些不知道 classA 是什么的 cpp 文件使用的标头上定义的类的成员。

这可能是防止分层违规的正当理由。

我必须在这些 cpp 文件中包含 classA 定义的标题,这有很多原因无法完成。

在您的情况下,这很可能没有必要。前向声明就足够了。如果标头知道要放入地图中的内容,但只是想避免包含其他标头,那么这就是要走的路。

于 2012-08-25T09:53:56.197 回答
6

正如约翰内斯解释的那样,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() { } 
于 2012-08-25T10:10:19.340 回答
2

仅仅因为地图的用户不应该知道实际类型而在标题中写入 void*并不是一个好主意,因为您在代码中的任何地方都失去了类型安全性,包括在知道 ClassA 的地方。

考虑

  1. 从代码的每个部分都可能知道的类派生 ClassA,
  2. 将地图包装到一个对象中,该对象为必须处理地图但不处理 ClassA 的那些代码部分提供接口,
  3. 在头文件中声明但未定义类 ClassA(如果在声明但未定义 ClassA 的某个位置销毁对象,则可能很危险),
  4. 使用模板,
  5. 将包含地图的类实现为派生子类,以便可以将地图字段放入派生子类中。

第 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 () { }
};
于 2012-08-25T10:05:04.267 回答