上对象层次结构

Going up the object hierarchy

本文关键字:层次结构 对象      更新时间:2023-10-16

嗨,所以我正在处理的程序中有一些不错的树层次结构。我遇到了传达底部到顶部的问题。我现在如何设置它的是,在每个构造函数中,我都会传达对创建新对象的对象的引用。简单的结构看起来像这样:
[控制器] -> [world] -> [对象]

上升一层(从世界到控制器或从对象到世界)是可以的。但是问题开始发生的地方是我尝试上2层。这是我如何设置它的简化结构:

Controller.H:

#include "World.h"
Class Controller {
public:
   Controller() {
      _worlds.push_back(World(*this));
   )
   void update() { // Called on a loop from main program loop
      _worlds[0].update(); // Calls update of active world, in this case world[0]
   }
   vector<World> _worlds;
   Camera _camera; // class with checkIfInView function
}

world.h:

#Include "Object.h"
Class Controller;
Class World {
   World(Controller& ref) : _controller(ref) {
      _objects.push_back(Object(*this));
      _controller._camera.doStuff(); // works OK
   }
   void update() {
      for (auto& i : _objects)
         i.update();
   }
   vector<Object> _objects;
   Controller& _controller;
}

object.h:

Class World;
Class Object {
   Object(World& ref) : _world(ref) {}
   void update();
   World& _world;
}

object.cpp:

#include "Controller.h"
#include "World.h"
void Object::update() {
   _world._controller._camera.checkIfInView(*this); // Read access violation
}

控制器持有一个负责显示的内容的单个相机对象。我需要的是对象调用checkifinview知道是否应该渲染的方法。还有其他方法可以解决此问题吗?

编辑:更新的代码。

问题

让我们看一下您的漂亮链,从Controller构造函数开始。由于它是您层次结构的首要对象,因此它的开始。我想在main()中您有类似

的东西
Controller c;  

这将导致构造函数称为:

 Controller() {
    _worlds.push_back(World(*this));    // !!! 
 }

World(*this)将创建一个新的临时世界,您将进入控制器世界的向量。临时对象仅在其出现的表达式时间内存在。

临时将使用

构建世界
World(Controller& ref) : _controller(ref) {  // ref to controller is kept 
    _objects.push_back(Object(*this));  // ouch!!! 
    _controller._camera.doStuff(); // works OK
}

现在将创建一个对象,指 *这个世界。哎哟!!还记得那个世界是暂时的吗?在构造结束时,它将被删除,以便所有对象都会引用不再存在的C 对象,因此在您的情况下会产生分割故障的UB。

解决方案的开始

您拥有的设计非常精致。如果找不到更安全的设计模式,请三思而后行。如果您想朝这个方向追求,请避免使用临时项目创建对象:而是动态分配的项目。

Controller() {
    _worlds.push_back(*new World(*this));    // !!! risk of leakage 
} 

接下来的事情是使用指针而不是参考:

Controller() {
    _worlds.push_back(new World(*this));    // risk of leakage 
} 

当然,您需要相应地更改代码的其余部分,以与指针一起工作。

接下来的事情是选择共享指针:这避免了泄漏的风险:

Controller() {
    _worlds.push_back(make_shared<World>(*this));    // risk of leakage 
} 

在适应代码的改编中,您需要在矢量中的共享_ptr之间有所作为,该矢量是指对象的,而弱_ptr则指示父母现在由孩子拥有,但是由另一个对象。

更好的解决方案?

我警告您,这不会是小菜一碟。一旦您有指针,您就需要照顾每个班级的3条规则。

许多问题来自:

1)嵌套的结构 ->可能值得考虑建造器设计模式2)混合静态对象和动态创建对象的风险,不知道父母是哪种。 ->可能值得使用受保护/私有构造函数,并使用工厂方法来确保所有对象始终是动态对象。