static_cast是否可以使用void *指针

时间:2012-08-25 09:47:03

标签: c++ casting

例如,建议map<int,void*>hold其中void*始终存储来自classA的指针,以后通过static_cast将其强制转换是否安全?

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

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

3 个答案:

答案 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。

考虑

  1. 从您的代码的每个部分可能知道的类中派生ClassA,
  2. 将地图包装到一个对象中,该对象为必须处理地图的代码部分提供接口,但不提供ClassA,
  3. 声明,但没有在头文件中定义类ClassA(如果在声明ClassA但未定义的某个地方销毁了对象,可能会很危险),
  4. 使用模板,
  5. 将包含类实现为派生子类,以便将map字段放入派生的子类中。
  6. 第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 () { }
    };