【问题标题】:c++ Setting a pointer variable in parent class from child and use it in parent classc ++在父类中从子类中设置指针变量并在父类中使用
【发布时间】:2011-07-03 10:16:43
【问题描述】:

我很抱歉标题。我好像有问题。我只是一个初学者,如果之前有人问过这个问题,我很抱歉。我无法找到一个直接的答案。 (当我搜索类、指针和子类时,我得到关于传递父或子指针的结果......我不想传递(这个)子或父指针,我只想传递我在子类上初始化的指针。 . 给父母)。我在这里尝试做的最好用代码来解释:

class App
{
public:
    virtual void init(void)         { window = &BasicWindow(); }
    virtual void createWindow(void) { window->create(); }

protected:
    Window *window;
};  

class Game : public App
{
public:
    virtual void init(void)         { window = &OpenGLWindow(); }
};

int main ()
{
    App *game = &Game();
    game->init();
    game->createWindow();
    return 0;
}

这合法吗? 我有一个抽象的 Window 类,BasicWindow 和 OpenGLWindow 派生自该类。 但是,当我创建窗口时,我在 App::createWindow() 函数内的 window->create() 处遇到 Access violation reading location 错误。

谢谢

【问题讨论】:

    标签: c++ class inheritance variables pointers


    【解决方案1】:

    我猜这是因为你指向一个临时的:

    window = &BasicWindow()
    

    一旦该函数退出,window 指向“废话”,就会发生坏事。

    大概,你想要做的是创建一个新的窗口实例 - 即

    window = new BasicWindow();
    

    别忘了清理!

    【讨论】:

    • 天啊,我现在感觉很愚蠢。谢啦!我以为我不必创建类的“新”实例,因为我只需要一个窗口。但似乎我误解了“在范围内使用一次”的部分。
    • @Nique,别这样,我敢肯定,在学习 C++ 的漫长而艰难的道路上,我们都犯过类似的错误...... :)
    【解决方案2】:

    window 是类App 的未初始化指针。因为,没有你在哪里调用init 方法。所以,当基类createWindow() 被调用时,window->create() 结果错误。

    编辑 1

    到目前为止,每件事在语法上都是正确的,但不确定您要达到的目标。不要创建临时/无名对象并分配它们。而是使用window = &BasicWindow();window = &OpenGLWindow(); 中的运算符new 构造它们。既然班级管理资源,就应该遵循Rule of Three的原则。也知道在声明中 -

    App *game = new Game();
    

    操作数的静态类型(App*)与动态类型(Game*)不同。在这种情况下,静态类型充当基类,它的析构函数必须是虚拟的,否则行为未定义。因此,App 类析构函数必须是虚拟的

    【讨论】:

    • +1 哎呀,我也错过了!! :D,我想我会留下我的答案,因为我认为它仍然有效!
    • 对不起,我重现了这种情况。事实上,我确实在 App->start(); 上调用了 init();
    • @edit 1,我不再需要在主要功能(或其他任何地方)中进行游戏。我真的需要创建对象的新实例吗?我的存档:以及在/任何操作系统中创建窗口的面向对象的方式。我不想在 main 中使用这些丑陋的消息处理器
    • Do i really need to create a new instance of the object? 是什么意思。实例和对象是同义词。如果您不再需要游戏实例,请在游戏实例上调用析构函数。您应该覆盖默认析构函数,因为类App 成员window 管理资源,如果使用运算符new 构造的话。检查三个链接的规则。而且,我不知道调用析构函数是否会对创建的窗口产生任何副作用。
    【解决方案3】:

    该错误可能与您使用指向临时对象的指针有关。

    virtual void init(void)         { window = &BasicWindow(); }
    

    这个指针在“;”之后变得无效。使用“新”而不是“&”。 如果您也想使用窗口指针,则需要调用 game->init()(最好放在构造函数中,这就是它们的用途)。

    除此之外,更改基类的受保护成员是完全合法的。

    【讨论】:

      【解决方案4】:

      我要赌一把,你来自 Objective-C? ;)

      我认为您的问题都源于不了解 C++ 对象是如何创建的。

      首先:window = &BasicWindow(); 不是您应该创建新对象的方式。您需要使用window = new BasicWindow; 这会导致在内存中为 BasicWindow 分配空间,并且将调用 BasicWindow 的默认构造函数。

      您的 main() 方法中也有类似的错误,但是在这种情况下,您不需要使用 new 来分配它,您只需声明一个实例,它将在堆栈上创建。

      您的主要方法将如下所示:

      int main ()
      {
          Game game;
          game.createWindow();
          return 0;
      }
      

      剩下的问题是你的 init 方法没有被调用。在 C++ 中,构造函数是自动调用的,并且与类同名。游戏类的默认构造函数示例如下:

      Game()  { window = new OpenGLWindow(); }
      

      您需要知道的另一件事是,与目标 C 不同,构造函数的整个层次结构在您创建对象时会自动调用。也就是说,当您创建 Game 的实例时,会调用它的构造函数,以及每个基类的构造函数。实际上,基类构造函数被称为 FIRST。因此,在您的情况下,如果您只是将 init 方法更改为构造函数,您将分配两个窗口(每种类型一个)并泄漏 BasicWindow。这不酷。

      您可能应该将它们命名为 init,并确保在创建后立即调用它。

      总之,试试这个:

      class App
      {
      public:
          virtual void init(void)         { window = new BasicWindow; }
          virtual void createWindow(void) { window->create(); }
      protected:
          Window *window;
      };
      
      class Game : public App
      {
      public:
          virtual void init(void)         { window = new OpenGLWindow; }
      };
      
      int main ()
      {
          Game game;
          game.init();
          game.createWindow();
          return 0;
      }
      

      (别忘了清理新的对象!)

      编辑(添加的示例完成清理):

      class App
      {
      public:
          App() : window( NULL )      {}
          virtual ~App()              { delete window; }
          virtual void init()         { window = new BasicWindow; }
          virtual void createWindow() { window->create(); }
      protected:
          Window *window;
      };
      
      class Game : public App
      {
      public:
          virtual void init()         { window = new OpenGLWindow; }
      };
      
      int main ()
      {
          Game game;
          game.init();
          game.createWindow();
          return 0;
      }
      

      【讨论】:

      • +1 不错的答案。如果你在 App 中添加一个虚拟析构函数会更好——也许是一个检查 window 是否是零指针,如果不是则删除它?
      • 我不是来自目标 C.. 我来自面向对象的 PHP 脚本。我知道关于构造函数和析构函数的故事。但是当我尝试更改父构造函数的窗口实例时,我感到很困惑。所以这正是我创建 init() 方法的原因。感谢您指出这一点!,无法更好地解释这一点。感谢您的有用回答。 (我在 main 中做得更干净) game.run() .. 和 run 负责执行 init() 和创建窗口。
      • @Tom 如果我们按照您所说的添加析构函数,我们还需要确保构造函数设置 window = NULL,否则它将是随机内存,并且在未初始化时很可能不为零。我不想走那么远并冒险让它混乱:)
      • @Alex 很公平,这是一个不错的答案
      • 我在游戏内的 destroy() 函数中清理(例如删除窗口;),它在主循环之后被调用(或者如果循环内发生任何错误).. 我希望这是正确的做法?
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-12-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多