【问题标题】:creating a derived class object with existing base class object?用现有的基类对象创建派生类对象?
【发布时间】:2011-07-20 21:22:42
【问题描述】:

是否有可能(或快速解决方法)创建定义为派生类的对象而不在内存中创建基类对象?相反,派生对象应该引用基类的实际存在的对象(“接管”其内存位置)?出于速度原因,这是必需的 - 创建新的派生对象,将数据从基类对象复制到它,然后销毁基类对象需要太多时间。

【问题讨论】:

  • 我不明白。您想在不复制的情况下将基类 X 的实例转换为派生类 Y 的实例?派生类中是否引入了新的字段?
  • 我想将基类的实例转换为派生类的实例,但不在内存中创建基类对象 - 创建派生类的实例应使用现有的基类实例作为其在内存中的一部分。是的,有新的领域。基类是一个“内存保护程序”——它只有始终需要的变量。

标签: c++ class memory object derived-class


【解决方案1】:

你考虑过工厂设计模式吗?

你的基类只需要知道你想创建什么样的派生类

【讨论】:

  • 添加一些解释,说明此答案如何帮助 OP 解决当前问题
【解决方案2】:

如果您希望创建基类的一个版本并让所有对象继承或派生自同一个实例,那么您可以在基类中将事物声明为静态。静态意味着类的每个实例都有一个版本。

class FooBase {
protected:
    static int IDCnt;
    static int ObjCnt;
    int ID;
public:
    FooBase();
    ~FooBase();
    virtual int GetID();
    virtual int GetObjCnt();
    virtual int GetIDCnt();
};
//implementation
int FooBase::IDCnt = 0; //need to init static vars
int FooBase::ObjCnt = 0;
FooBase::FooBase() { ID = IDCnt; IDCnt++; ObjCnt++; }
FooBase::~FooBase() { ObjCnt--; }
int FooBase::GetID() { return ID; }
int FooBase::GetObjCnt() { return ObjCnt; }
int FooBase::GetIDCnt() { return IDCnt; }

#include "FooBase.h"
class FooDerived : public FooBase {
      //blah

};
#include "FooDervied.h"

int main() {
FooDerived A;
FooDerived B;
cout << A.GetID() << ' ' << A.GetObjCnt() << ' ' << A.GetIDCnt() << endl;
cout << B.GetID() << ' ' << B.GetObjCnt() << ' ' << B.GetIDCnt() << endl;
if(true) {
   FooDerived C;
   cout << A.GetObjCnt() << ' ' << A.GetIDCnt() << ' ' << B.GetObjCnt << C.GetIDCnt() << endl;
}
cout << B.GetObjCnt() << '' << A.GetObjCnt() << ' ' << A.GetIDCnt() << ' ' << B.GetIDCnt << endl;

}

通过这种方式,您无需声明基类项,而是通过静态变量继承基类的实例,这基本上意味着所有 FooDerived 都在为 FooBase::IDCnt 和 @ 查看同一块内存987654324@。

【讨论】:

    【解决方案3】:

    如果要动态调用派生类,v-table是必不可少的。

    所以也许你可以在没有数据成员的情况下实现“基类”,并在调用过程中传入虚拟函数需要的数据或数据指针作为参数。

    这样会节省内存,但会花费更多时间。

    【讨论】:

      【解决方案4】:

      我不会使用该语言支持的 class 构造。如果您需要一些小而灵活的东西,请考虑编写struct 并使用函数指针实现您自己的v-table。例如,在 Linux 内核中,这样做的方式与此大致相同。请注意,面向对象编程几乎可以用任何语言完成,不一定是支持它的语言。

      然后您可以即时切换 v-table 指针,并可能执行一些realloc 以添加派生类型所需的字段。

      最后,您可以将所有这些打包在一个没有任何动态方法的常规 class 中,而只是将所有调用委托给所描述的内部结构。这不应强加任何内存或计算开销。

      编辑:实际上我猜realloc 不是要走的路。这是一个涉及底层操作系统并需要上下文切换的例程。如果您已经分配了适当的内存块,几乎总是调用copy 会更快。如果您对速度感兴趣,那么也许还可以考虑实现自己的内存管理或使用库提供的替代实现之一,例如 boost。

      【讨论】:

      • 嗯...这可能是它...我会考虑实现我自己的 v-tables。但是如何即时切换 v-table?我认为这一切在 C++ 中都是可能的,是吗?
      • 我的意思是模仿语言内置特性的实现。通常,类有一个指向方法实现表的指针。一旦调用了动态方法,首先在 v-table 中查找适当的实现。在这种情况下,切换 v-table 意味着为每个实例中保存的 v-table 指针分配一个新值。见:en.wikipedia.org/wiki/Virtual_method_table
      【解决方案5】:

      我不认为你可以做你想做的事。

      考虑:

         d1 = prestochango(b);
         d2 = prestochango(b);
         d1.blarf = waldo;
         // what value does d2.blarf now have?
      

      要么 d1 和 d2 是不同的对象,包括不同的 b 底物,要么它们是同一个对象。

      现在,您可以通过使您的 b-substrate 成为您的 d 类的静态成员来伪造它。

      【讨论】:

      • 我打错字了:“...在派生中定义...”应该是“...定义为派生...”(已经更改),抱歉英语不是我的主要语言。我想要什么:当创建派生类的实例时,编译器通常会在内存中创建基类和派生类变量 - 我需要其他行为:我需要“接管”现有实例基类变量而不是创建基类变量(所以没有需要销毁基类对象,只在内存中创建派生类变量)
      • 在这一点上,我相信不可能做到你说你想做的。
      【解决方案6】:

      在这种情况下,您可能需要考虑组合而不是继承 - 这会更自然。

      【讨论】:

      • 感谢超快的回答:D 但据我所知,组合需要在“整体”类对象中包含“部分”类变量,这是一个问题,因为我需要“整体”类最小尽可能 - 即使包含指向“部分”类的指针也太多了 - “整个”类(或我的问题方法中的基类)是内存保护程序,我在这里谈论字节......
      猜你喜欢
      • 1970-01-01
      • 2015-08-10
      • 2020-08-06
      • 1970-01-01
      • 2020-03-17
      • 2017-02-26
      • 1970-01-01
      • 1970-01-01
      • 2020-08-12
      相关资源
      最近更新 更多