【问题标题】:c++ private object of another class: initialization and use it to call a function in that classc ++另一个类的私有对象:初始化并使用它来调用该类中的函数
【发布时间】:2025-11-26 05:35:01
【问题描述】:

我有两个类 AB,其中类 B 看起来像

B.h

class B
{
 public:
    B();
    virtual ~B();
    void eval(int a, int b);
 private:
    A* APointer;
};

相应地我有

B.cpp

B::B():APointer(NULL){}
B::~B(){}

void B::eval(int a, int b)
{
   if a == b
      {
      APointer->run(); // run() is a public method defined in class A
      }
}

那么A类就是这样的:

A.h

#include "LuaBridge.h"
extern "C" {
#include "lua.h"
#include "lualib.h"
#include "lauxlib.h"
}
using namespace luabridge;

class LuaParser
{
  public:
    LuaParser(lua_State* L);
    virtual ~LuaParser();
    void run();

  private:
    LuaRef mRun;
    LuaRef mStop;
    lua_State* mL;
};

还有

A.cpp

LuaParser::LuaParser(lua_State* L) :mRun(L),mStop(L),mL(L) {}
LuaParser::~LuaParser(){}

void LuaParser::run(){
std::cout<<"This project runs!"<<std::endl;
}

系统很复杂,实际上我在类C成员函数中调用了这个eval函数。在那个类中,我通过B* BPointer 定义了一个私有成员BPointer,在构造函数中我做了C(B* BPointer = NULL),然后我只是在类C 成员函数中使用BPointer-&gt;eval(a,b)

在我的 main 代码中,我在 B 类中定义了一个指针,如 B* BPointer,我使用该指针调用方法 B::eval by

BPointer -> eval(a, b);

但是,当我在 Visual Studio 中逐步运行它时,在命令行APointer-&gt;run(); 我注意到this 指针类似于:

Value: 0xcdcdcdcd{APointer=???}

当我尝试运行此命令时,出现错误:

Access violation reading location 0xCDCDCDD1.

嗯...我不知道如何解决这个问题,我想知道的是:

  1. 整个想法(即在此类的方法中使用私有对象调用另一个类的函数)是否可行?

  2. 如果这个想法可行,那我应该如何修改我的代码呢?

欢迎提出任何建议或想法!

【问题讨论】:

  • 请提供APointer和BPointer的初始化代码(如有)
  • 您正在使用未初始化且无效的指针。为什么会有这么多指针?

标签: c++ class private


【解决方案1】:

是整个想法(即使用私有对象调用函数 这个类的方法中的另一个类)是否可行?

是的,这很常见。

如果这个想法可行,那我应该如何修改我的代码呢?

您需要了解对象和指针之间的区别。指针是内存区域的地址,甚至可能未分配。

这里有两个指针不指向任何分配的内存,因此没有可以调用其方法的对象。

BPointer 是未初始化的,它包含随机内存区域的地址(或调试版本中的幻数 0xcdcdcdcd),其中可能包含任何属于或不属于你的东西。取消引用它是undefined behavior。为避免这种情况,您应该创建B 对象并将其指针分配给BPointer

B *BPointer = new B;

在你使用完BPointer之后,你应该释放内存并通过调用来调用B的析构函数

delete BPointer;

APointerNULL 指针初始化,这意味着它不指向任何内存区域。取消引用 NULL 也是未定义的行为。和BPointer类似,应该用有效的对象指针初始化,稍后释放:

B::B() : APointer(new A(/* lua state pointer */ NULL)) {}
B::~B() { delete APointer; }

如果您不一定需要指针,我建议对B 使用堆栈分配并将A 存储为普通成员(而不是指针)。这样您就无需为指针初始化和删除而烦恼。

B.h

class B
{
 public:
    B();
    void eval(int a, int b);
 private:
    A AObject;
};

B.cpp

B::B() : AObject(/* lua state pointer */ NULL) {}

void B::eval(int a, int b)
{
    if (a == b) 
    {
        AObject.run();
    }
}

main.cpp

// ...
B b;
b.eval()
// ...

【讨论】:

  • 感谢您的解释!但是在你的回答中,在最后一部分的 B.cpp 中,它应该是 AObject.run() 吗?我什至不需要初始化 AObject ?
  • @gladys0313 你完全正确,应该是AObject.run()。编辑了答案。
  • @gladys0313 如果一个对象有默认构造函数(即没有参数),默认构造函数被隐式调用。如果 A 不能被默认构造(正如我从你更新的问题中看到的那样),你仍然需要在 B::B() 构造函数的初始化列表中传递它的参数。
  • 很抱歉,我没有理解B::B(): AObject(/* lua state pointer */ NULL) {} 的意思,请您指导如何编写此初始化程序?我尝试使用lua_State* L = NULL;B::B(): AObject(L) {}。编译成功但是运行的时候遇到了另一个问题叫Access violation reading location 0x0000000F.这个问题好像和Lua有关.....
  • @gladys0313 似乎 LuaParser(a.k.a. A) 并不意味着用 NULL lua_State 初始化。将LuaParser 认为有效的值传递给那里。不幸的是,我无法说明如何初始化这个类。
【解决方案2】:
0xcdcdcdcd

是已分配但尚未初始化的内存的状态。您是否以适当的方式实例化了您的BPointer?例如

BPointer = new B(); 

除了你的 APointer 是 NULL 所以你不能调用任何方法

APointer->run();

在构造 A 类型的对象并将其也分配给 APointer 之前。

【讨论】:

  • 感谢您的想法!我的 BPointer 应该没问题,因为我放在函数体中的是一个简化的,我还有一些其他命令,它们运行良好..但是当你说“在你构造一个 A 类型的对象之前,我没有明白也将其分配给 APointer。”你能解释更多吗?
  • 为了使用指针(通过它调用方法),它必须指向执行这些调用的某个对象。您的 APointer 没有指向任何地方(它为 NULL),因此您无法在其上调用方法。您需要做的是将对象的地址存储在 APointer 中。您可以通过在堆栈上构造一个对象并存储其地址A a; APointer = &amp;a; 或在堆中构造它(使用new)APointer = new A(); 来做到这一点。之后,您的 APointer 存储实际对象的地址。
【解决方案3】:

您必须在 B 类的构造函数中使用一些真实对象初始化 APointer 数据成员。它应该如下所示,

B::B()
{
   this->APointer = new A();
}

B::~B()
{
  delete this->APointer;
  this->APointer = NULL;
}
...
...

int main()    
{
   B* BPointer = new B();

   int x = 5;
   int y = 5;

   BPointer->eval(x, y);
}

在您上面提到的代码中,APointer 被初始化为NULL。我认为当B::eval()被执行时,会导致一些未定义的行为。

如果你也能贴出A类的代码就好了。

【讨论】:

  • @gladys0313 您能否编辑您的问题以显示 A.h、A.cpp 和 main.cpp ...我认为 APointer 仍然没有被正确初始化