尝试将对象存储在数组中,但如何调用该对象的方法?

Trying to store an object in an array but then how to call that object's methods?

本文关键字:对象 调用 方法 何调用 存储 数组      更新时间:2023-10-16

我不是一个经验丰富的c++程序员,这让我很困惑。我将一个对象(在其他地方创建)传递给一个函数,我希望能够将该对象存储在某个数组中,然后运行该数组来调用该对象上的函数。这里有一些伪代码:

void AddObject(T& object) {
  object.action(); // this works
  T* objectList = NULL;
  // T gets allocated (not shown here) ...
  T[0] = object;
  T[0].action(); // this doesn't work
}

我知道对象的传递是正确的,因为对object.action()的第一次调用做了它应该做的事情。但是,当我将对象存储在数组中,然后尝试调用action()时,会导致大崩溃。

很可能我的问题是我只是修修补补在编译之前,T[0].action()会编译,但在运行时崩溃。

问题的最简单答案是必须正确声明容器必须为类定义适当的赋值运算符。从你的例子中尽可能紧密地工作:

typedef class MyActionableClass T;
T* getGlobalPointer();
void AddInstance(T const& objInstance)
{
    T* arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **objects**
//whose first element we don't mind losing
//**copy** the instance we've received
    arrayFromElsewhere[0] = objInstance;
//now invoke the action() method on our **copy**
    arrayFromElsewhere[0].action();

}

请注意签名更改为const-reference,这强调我们将复制原始对象,而不是以任何方式更改它。

此外,请注意arrayFromOtherwhere[0].action()与objInstance.action()不同,因为您已经复制了一个副本--action()在不同的上下文中被调用,无论多么相似。

虽然很明显您已经进行了压缩,但压缩使这样做的原因变得不那么明显——例如,指定要维护一个回调对象数组将为"需要"此功能提供更好的理由。像您那样使用"T"也是一个糟糕的选择,因为对于大多数有经验的C++程序员来说,这往往意味着模板的使用。

最有可能导致你"无法解释"的崩溃的是分配运算符;如果您不定义一个,编译器将自动生成一个可以作为逐位副本的副本——几乎可以肯定的是,如果您的类不是简单数据类型(POD)的集合,则不是您想要的。

为了在任何复杂的类上正常工作,您可能需要定义一个深度副本或使用引用计数;在C++中,让编译器为您创建任何ctor、dtor或赋值几乎总是一个糟糕的选择。

当然,最好使用标准容器,而不是示例中所暗示的简单数组机制。在这种情况下,由于容器和算法所做的假设,您可能还应该定义一个默认的ctor、一个虚拟dtor和一个复制ctor。

事实上,如果不想创建对象的副本,而是想在数组中对原始对象调用action(),那么您将需要一个指针数组。再次紧密结合您的原始示例:

typedef class MyActionableClass T;
T** getGlobalPointer();
void AddInstance(T& objInstance)
{
    T** arrayFromElsewhere = getGlobalPointer();
//ok, now at this point we have a reference to an object instance
//and a pointer which we assume is at the base of an array of T **pointers**
//whose first element we don't mind losing
//**reference** the instance we've received by saving its address
    arrayFromElsewhere[0] = &objInstance;
//now invoke the action() method on **the original instance**
    arrayFromElsewhere[0]->action();

}

请注意,arrayFromOtherwhere现在是指向对象的指针数组,而不是实际对象数组。

注意,在这种情况下,我删除了const修饰符,因为我不知道action()是否是const方法——我假设它的名称不是…

请仔细记下分配中使用的"与"和(地址)运算符。

还要注意使用指针到运算符调用action()方法的新语法。

最后要注意的是,使用指针的标准容器充满了内存泄漏的危险,但通常情况下,不会像使用裸数组那样危险:-/

我很惊讶它能编译。您声明了一个数组objectList,它包含指向T的8个指针。然后分配T[0] = object;。这不是你想要的,你想要的是

T objectList[8];
objectList[0] = object;
objectList[0].action();

T *objectList[8];
objectList[0] = &object;
objectList[0]->action();

现在我正在等待一位C++专家来解释为什么要编译你的代码,我真的很好奇。

您可以将对象放入动态或静态数组:

#include <vector> // dynamic
#include <array>  // static
void AddObject(T const & t)
{
    std::array<T, 12> arr;
    std::vector<T>      v;
    arr[0] = t;
    v.push_back(t);
    arr[0].action();
      v[0].action();
}

不过,这并没有多大意义;您通常会在函数之外的其他地方定义数组。