【问题标题】:Can you do a pointer to a class in c++?你能在 C++ 中做一个指向类的指针吗?
【发布时间】:2020-01-06 04:58:59
【问题描述】:

注意:我不是指指向 OBJECT 或 INSTANCE 的指针,而是指指向 CLASS 的指针

我把它放在顶部是因为我知道如果我不这样做,人们会告诉我我可以做到

class MyClass;
MyClass* pointerToMyClass = new MyClass(); // Ta-da! pointer to class!

这不是我要找的。我想创建一个指向类类型本身的指针,有点像函数指针,但是对于一个类。

为了更清楚我的要求,这里有一些代码大致展示了我在寻找什么。

class MyClass; // real Class
class MyDerived : public MyClass; // derived class

class * ClassPointer = &MyClass; // pointer to my class
MyClass * instanceOfPointer = new ClassPointer(); // now makes an instance of MyClass

ClassPointer = &MyDerived; // pointer to derived class
MyClass * instance2 = new ClassPointer(); // now makes an instance of DerivedClass

有点像 typedef,但更具动态性。

我还希望能够制作一个类指针向量。目前,我正在使用类函数clone() 来破解我需要的行为,该函数返回一个指向基类的新指针,但我并不特别喜欢这种方法。

在 C++ 中有这样的可能吗?

编辑: 我正在使用它的当前问题是多态网络协议。 有一个基础数据包类:

class packet{
    int id=0;
    virtual packet* read(); // read packet type into id
    virtual packet* clone(){ return new packet(); }
};

然后是多个派生数据包:

class packet1 : public packet{
    int id=1
    packet* read(); // do packet specific reading
    packet * clone(){ return new packet1(); }
};

class packet2 : public packet{
    int id=2
    packet* read(); // do packet specific reading
    packet * clone(){ return new packet21(); }
};

class packet3 : public packet{
    int id=3
    packet* read(); // do packet specific reading
    packet * clone(){ return new packet3(); }
};

那么你需要做的就是读取一个数据包

packet* array[] = { new packet(), new packet1(), new packet2(), new packet3() }; // array of packets, this should be class* if possible
packet type = packet();
type.read(); // read type from network
packet* data = array[type.id].clone(); // pick derived class based on type
data->read(); // read specific packet from network

packet*[] 将替换为 class*[] 以避免必须使用 clone()

这是一个简化但可行的示例。

【问题讨论】:

  • 没有。这不可能。但是您可以解释您遇到的问题并寻求可能的设计解决方案。但是,由于缺少反射,并且模板元编程困难且不可读,C++ 中存在一些限制。
  • 这甚至没有意义。想想你会如何使用它,用一种硬类型的语言。您可能想看看模板。
  • 您能否解释一下您不喜欢的clone 方法,以便我们知道您想要哪种解决方案?是否需要有一个类的实例? (因为如果是这样,那很容易解决。)
  • 你可以玩std::decltype,但这似乎不切实际。模板就是这样做的方法。
  • 由于您唯一需要做的就是默认构造它,因此您可以使用静态函数。 (这是一件好事,因为如何确定每个派生类都有一个公共的默认构造函数?)template<typename T> T* make<T>() { return new T(); },然后你可以做到using packet_maker = packet*(*)(); *packet_maker[] array={make<packet>, make<packet1>, make<packet2>, make<packet3> };

标签: c++ class pointers


【解决方案1】:

不,这是不可能的,因为类型必须在编译期间解析。您“物理地”编译指令如何创建新对象。当然,您可以使用 RTTI 基于 typeinfo 的简单条件使其可变。

#include <typeinfo>
MyClass *createInstanceOf(const std::type_info& myType)
{
    if (myType == typeid(MyClass))
        return new MyClass();
    if (myType == typeid(MyDerived))
        return new MyDerived();
    // handle invalid type
}

这样您可以根据运行时变量(即变量 std::type_info)创建不同的对象。

class MyClass;//real Class
class MyDerived: public MyClass;//derived class
std::type_info myType = typeid(MyClass);//pointer to my class
MyClass * instanceOfPointer = createInstanceOf(myType);//now makes an instance of MyClass
myType = typeid(MyDerived);//pointer to derived class
MyClass * instance2 = createInstanceOf(myType);//now makes an instance of DerivedClass

重要的部分是这个函数知道应该在哪个对象创建中编译(您想要支持的所有类型),在运行时决定采用哪条路径,但在编译代码时知道创建本身。类型永远不能是可变的。甚至模板也不是变量,它们为编译期间实例化的每种类型生成函数/类的实例。

我要补充一点,这个解决方案仅在非常特殊的情况下才有用。本质上,如果您在编译期间知道类型,那么您永远不应该保存类型的 type_info,然后在条件下使用它来获取类型。它会比应有的重得多,并且几乎不可能优化。

您的示例似乎缺少一些东西。据我了解,您要做的就是从外部源读取类型,然后根据此变量类型读取数据。这是阅读任何外部通信的非常标准的方式,并且或多或少地以我上面提到的方式完成。您需要运行时决策机制,该机制将采用适合给定类型的路径。在某些时候,您必须做出此决定,因为您的代码必须分支并到达适当的处理程序(在您的示例中似乎是数据包)。 在这种情况下,您不应使用 typeid,因为它只能保证在一次程序执行中对于同一类型是唯一且相同的 - 它不能共享或存储以供下次执行。在您的情况下,您需要自己的类型信息(通常 enum 是最有效的)。这样您就可以创建处理程序的地图。如果数据包的类型已知且定义明确,那么您可以从 0 开始按顺序将它们存储在具有恒定访问时间的规则数组中。这是最有效的方法之一。本质上是你的type.id

【讨论】:

    【解决方案2】:

    最好的答案从来都不是一个答案,感谢 Raymond Chen

    不,您不能使用指向类的指针(实际上禁止使用构造函数的指针http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2005/n1905.pdf 12.1.12),但是您可以通过

    template<typename T> T* make<T>() { return new T(); }
    

    并取make&lt;classToPointTo&gt;的函数指针

    比我的克隆功能要好得多,我不希望这个精彩的答案在剩下的时间里埋没在 cmets 中。

    【讨论】:

    • 我不认为它回答了您主题 Can you do a pointer to a class in c++? 的问题,请考虑更新主题以反映您真正想要实现的目标。
    • 我不知道我会如何改变话题,但在我看来,它很好地回答了这个问题,我编辑了答案可能会更好地回答
    猜你喜欢
    • 2010-09-22
    • 1970-01-01
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 2021-04-07
    • 1970-01-01
    相关资源
    最近更新 更多