2

一个具体的问题:

我有一个主应用程序,它具有 A 类型和 B 类型(以及其他类型)的对象。B类型的对象需要正确构造A对象(因此有一个构造函数A(const B&b)。但是Main可能随时更改它持有的B对象。我如何确保当Main更改其B对象时一个对象的内部引用被改变了?

一般来说,在对象具有依赖关系的情况下,管理对象生命周期的一些好的做法是什么?

4

6 回答 6

3

如果A从不缓存任何B属性,并且始终引用B它持有的实例以生成任何依赖输出,则对 所做的任何更改B都应反映在对A. 我假设您只是B在构造函数中存储对的引用,而不是创建本地副本。

于 2011-07-18T15:55:35.507 回答
1

如果我理解正确,您不仅要更改 B 对象,还要用不同的 B 完全替换它。引用一旦创建就不能更改,因此您需要改用指针。

您可能希望使用观察者模式让 A 对象知道何时应该替换它们的 B:http ://en.wikipedia.org/wiki/Observer_pattern

于 2011-07-18T16:08:39.127 回答
0

如果我理解正确,如果您对 main 持有的对象进行修改,它应该反过来影响A持有的对象。为此,您可以借助构造函数初始化程序。

#include <iostream>

class B{
    public:
        int num ;
        B(int arg):num(arg) {}
};

class A{
    public:
        const B& ref ;
        A( const B& arg ): ref(arg){}
};

int main()
{
        B objOne(10) ;
        A objTwo(objOne) ;

        std::cout << objTwo.ref.num << std::endl ;
        objOne.num = 20 ;
        std::cout << objTwo.ref.num << std::endl ;
}

输出 :

10
20

于 2011-07-18T15:59:29.417 回答
0

记住:

  1. 所有问题都可以通过多一层间接来解决。
  2. 对象所有权必须是显而易见的。

在您的情况下,如果B实例可以随时来去(旧实例被删除,新实例被“新建”),那么您可以创建一个“包装”B实例的“实用程序句柄”类:

class BHandle {
  B* b_; // can change at any time
  public:
    ....
};

然后,您的A类将引用一个BHandle实例,或完全包含一个BHandle实例。然后,B实例可以来来去去,但A::my_b_handle_总是会反映“当前”B实例的位置。

另一方面,如果B实例仅具有更改的数据成员(它的实例本身不会来来去去),那么您不需要做任何事情(A将始终引用同一个B实例,并且在某些情况下您可能会只需要“通知”它引用A的对象中的属性发生了变化)。B

于 2011-07-18T16:01:02.377 回答
0

一般来说:始终确保您了解所有权。每当您创建一个对象时,另一个对象必须是所有者,或者它必须是局部变量。在您的情况下,主例程将是 B 实例的所有者。如果您在 A 实例中有对 B 的引用,A 将看到对实例的所有更改 - 只要确保您不复制(没有引用确实隐式复制)。所以在你的代码中你会有类似的东西

private:
  const B& theReference;

或者

private:
  B& theReference;

如果您需要调用非常量方法(请记住在这种情况下还要更改您的构造函数)。

于 2011-07-18T15:55:51.543 回答
0

这是我处理问题的方法。用户代码如下所示:

class Env
{
public:
   Env();
   ~Env();
private:
   void *priv;
};
class MyInterface
{
 public:
  MyInterface(Env &e) : e(e) { }
  int create_A();
  void use_A(int a);
 private:
   Env &e;
   void *priv; 
 };
 int main()
 { 
    Env e;
    MyInterface i(e);
    int a = i.create_A();
    use_A(a);
 }

这样每个依赖项在用户代码中都是可见的。对象之间的依赖关系很好地存储在 Env 类的 std::vectors 中。向量的索引将从函数返回。create_A() 和 use_A() 可以通过整数进行通信。当 Env 类超出范围时,所有对象将同时销毁。您的对象可能来自具有虚拟析构函数的基类。

如果您有多个 int,推荐的方法是:

struct ID { int i; };

接口的实现将依赖于以下功能:

A *find_a(const Env &e, ID i);
ID create_a(Env &e, A *ptr);

上述方法解决了对象生命周期的以下问题:

  1. 对象的生命周期
  2. 对象之间的依赖关系(通过整数)
  3. 识别对象
  4. 依赖关系可以通过 int 或通过指针存储
  5. 生命周期结束时销毁对象
于 2011-07-18T16:02:43.537 回答