【问题标题】:C++ initialising a class pointer through a functionC ++通过函数初始化类指针
【发布时间】:2018-05-28 04:54:02
【问题描述】:

我有一个程序,它有一个class A 类的实例和多个class B 类的实例,其中class B 的每个实例都有一个指向class A 的单个实例的指针。我想我可以在main() 中启动它们,然后将class A 的单个实例的地址传递给class B 的所有实例。我想知道这是否正确,我一直在研究继承,但根据我的理解(这通常是错误的),如果您继承另一个类,那么该类每次都会被启动,因此会创建多对多关系,而我想要一个太多。我附上了一些代码。任何建议将不胜感激。

// C/C++ standard library
#include <vector>
#include <iostream>
#include <cstdlib>

using namespace std;

class A {
public:
    double get_value(void) {
        return value;
    }
private:
    double value;
};


// Forward declare A if split over files
class B {
public:
    void assign_pointer(A class_a_to_assign) {
        class_a = &class_a_to_assign; // assign the pointer the address to point to
    }
    void update_my_value(void) {
        value_b += class_a->get_value();
    }

    double get_value(void) {
        return value_b;
    }
private:
    double value_b = 0.1;
    A* class_a; // pointer to class A
};

int main() {
    cout << "hello world" << endl;
    // create 2 instances of B there could be thousands of these tho.
    B b1;
    B b2;
    // create 1 instance of A
    A a1;

    // Now I want both instances of the B class to point to the one instance of A
    b1.assign_pointer(a1);
    b2.assign_pointer(a1);

    // THen do stuff with B so that if any changes occur in A, then they can be automatically updated in class B through the pointer

    b1.update_my_value();
    b2.update_my_value();

    cout << b1.get_value() << " and " << b2.get_value() << endl;
    return 0;
}

【问题讨论】:

  • 一个改进是在所有B 对象之前创建a1,以确保它比它们更长寿,因为它们依赖于它。
  • 继承不是多对多的,它只是每个对象的一对一关系。 (此外,A 的前向声明不足以满足 B 的定义,并且您的示例读取自未初始化的 A::value。)这里没有其他(显然)错误(即使可以做出重大改进)——这就是你的全部问题吗?
  • 另一个:确保 B 只能从 A* 实例化,方法是在构造函数中进行:explicit B(A* a) : class_a(a) {}

标签: c++ class pointers


【解决方案1】:

首先,您的代码中有一个严重的问题:

void assign_pointer(A class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

这里,class_a_to_assign 是一个按值函数参数,就生命周期而言,它与任何函数局部变量大致相同。换句话说,一旦控制离开方法的作用域,class_a 就变成了一个悬空指针(一个指向不再存在的本地对象的指针)。快速修复简单明了:

void assign_pointer(A &class_a_to_assign) {
    class_a = &class_a_to_assign; // assign the pointer the address to point to
}

区别只是一个字符 - 函数参数声明中的 & 符号将其从临时值转换为对更长寿对象的引用。

接下来,如果您有一个 class A 的对象,您是否考虑过将其设为单例?这样,B 的实例甚至不需要保留该指针,A 自己管理该实例。那里有很多关于设计单例类的说法,粗略而幼稚的实现类似于:

class A {
    A(); // note it's private
public:
    int getValue() const;
    static A &instance() {
        static A retVal;
        return A;
    };
};

class B {
public:
    void update_my_value(void) {
        value_b += A::instance().get_value();
    }
};

int main() {
    A::instance(); // to warmup the static instance before any users are created
    B b1; // no assign_pointer is needed as A is a Singleton
    B b2; // and every B always knows where to find it
}

【讨论】:

    【解决方案2】:

    下面的函数违反了您只创建一个A 实例并使用指向该A 实例的指针的意图。

    void assign_pointer(A class_a_to_assign) {
        class_a = &class_a_to_assign; // assign the pointer the address to point to
    }
    

    由于您按值接受class_a_to_assign,因此您有两个问题:

    1. 每次调用该函数时,您都会创建一个 A 的新实例。
    2. 您正在存储一个指向临时对象的指针。一旦函数返回,指针就会变成无效指针。

    您可以通过将参数设为引用类型来解决这两个问题。

    void assign_pointer(A& class_a_to_assign) {
        class_a = &class_a_to_assign; // assign the pointer the address to point to
    }
    

    另外,正如 cmets 中提到的,最好在 B 对象之前创建 A 对象,因为您希望 AB 对象更长寿。

    int main() {
        cout << "hello world" << endl;
    
        // create 1 instance of A
        A a1;
    
        // create 2 instances of B there could be thousands of these tho.
        B b1;
        B b2;
    
        ...
    }
    

    【讨论】:

      【解决方案3】:

      您所描述的内容听起来很像singleton。通常处理这种情况的一种方法是让单例类包含一个static 方法,该方法返回该类的单个实例。所以它看起来像这样:

      class A {
          public:
              A() { /* constructor */ }
              ~A() { /* destructor */ }
              static A* getInstance();
              double get_value(void) {
                  return value;
              }
          private:
              double value;
      }; 
      

      static 方法在实现 (.cpp) 文件中看起来像这样:

      static A gSharedInstance;
      
      static A* A::getInstance()
      {
          return &gSharedInstance;
      }
      

      这会在静态初始化时构造一个A,当调用上述方法时,它会返回一个指向该静态共享实例的指针。现在,无论您想在哪里使用A,您都可以这样做:

      A* sharedA = A::getInstance();
      double value = sharedA->getValue(); // Or whatever you need from it.
      

      注意,单例本质上是一个全局变量,全局变量有一些问题。 (例如,在这种情况下,它的value 成员集在哪里?)但是如果该类表示一些真正独特的资源(例如设备上唯一的麦克风),那么值得用一个单例来表示它。在这种情况下,最好将其设为只读,这样它的状态就不能在许多不同的地方设置。另外,请注意,您可能需要添加代码来处理同时访问它的多个线程。

      【讨论】:

        猜你喜欢
        • 2022-01-09
        • 1970-01-01
        • 2015-03-04
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多