【问题标题】:Initialize a vector of classes that have member pointers to another class' member variables初始化具有指向另一个类的成员变量的成员指针的类向量
【发布时间】:2020-10-20 00:05:00
【问题描述】:

对于科学代码,我需要构建需要(成员)指向其他类(即父级和兄弟级)成员变量的指针的类。

我已经研究了几个小时,发现了几个关于指向成员变量的指针的主题,但没有关于我的具体问题。因此我的问题是:在下面的示例中实例化类 C 以使类 C 中的指针指向类 B 中的 VectorXd beta 的正确语法是什么?

编辑:为了澄清我的问题,预期的行为是调用 B 类成员函数 PrintBetas() 打印出 VectorXd beta nr_C 次的当前值。

#include <iostream>
#include <vector>
#include <Eigen/Dense>

using namespace Eigen;
using namespace std;


class C {
    
  public:    
    C( VectorXd *beta_IN ): beta( beta_IN ) {}
         
    void PrintBeta() {
      cout << "(*beta) = " << (*beta).transpose() << endl;  // ???
    }    

  private:
    const VectorXd *beta;
};


class B {
      
  public:            
    B( VectorXd beta_IN, int nr_C ): beta( beta_IN ) {
      for( auto i=0; i<nr_C; i++)
        vec.push_back( C( &beta ) );
    }
    
    void PrintBetas() {
      for (auto c : vec)
        c.PrintBeta();
    }

    VectorXd beta;
            
  private:    
      
   vector<C> vec;
          
};


class A {
  
  public: 
    A( int nr_B, int nr_C ) {
          
      for (auto i=0; i<nr_B; i++) {
        VectorXd beta = VectorXd::Random(3);
        subclass.push_back( B( beta, nr_C) );
      }
   }
   
   vector<B> subclass;
};
  
  

int main() {
    
  A test(2,3);
  test.subclass[0].PrintBetas();
  test.subclass[1].beta.setZero();
  test.subclass[1].PrintBetas();
  
}

【问题讨论】:

  • 正确的语法取决于你想要做什么。我宁愿不要试图从有缺陷的代码中推断出你的意图。 (如果您的代码没有缺陷,您就不会问这个问题。)请描述您要完成的工作。理想情况下,您的描述将足够抽象,以至于提及您的类层次结构只是在示例代码之前添加的一些上下文。 提示:描述可能以“我希望beta 指向...”开头。
  • 您确定:that require (member) pointers。这似乎是一个奇怪的用例。更标准的技术是使用 std::function&lt;int()&gt; 然后它可以是任何类型的可调用而不是特定类型。
  • @JaMiT:好点。在我的示例中,我希望 C 类中的 beta 指针指向 B 类中的 beta 向量,因此 C 类成员函数可以将 beta 值打印到屏幕。
  • @Marzz C 中的指针是否有原因必须 指向B 的成员?我认为您正在设置自己使用pointer to class data member(另请参阅cppreference.com),但为什么不简单地使用指针,如VectorXd*
  • @JaMiT:我研究了那篇文章,关于侵入性列表的示例与我所寻找的非常接近。唉,我仍然无法让 C 中的指针指向 B 中的成员,因此这个问题。如果您知道应该如何在 C++ 中完成,请告诉我!至于成员指针的原因,在我的计算中,这是 C 类中最优雅的设计。即使有另一种方法,我真的很想知道如何使用指向另一个类的成员变量的成员指针来初始化一个类:)

标签: c++ pointers


【解决方案1】:

在您的代码中,每当您复制 B 对象时,新 B 中的 Cs 仍指向旧 B 中的 beta 成员。这是您要解决的问题。

选项 1:仅使用 B 指针,包裹在智能指针中,如或 shared_ptr。现在,当您复制它时,它不会复制底层 B 对象,并且所有 C 都保持不变。

选项 2:复制 B 时,重载复制构造函数以调整所有底层 C 以指向新对象的 beta 成员:

B::B(const B& other)
  : beta(other.beta),
    vec(other.vec)
{
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        it->beta = &beta;
    }
}

这可能看起来很昂贵,但无论如何你都在复制所有的 C,所以它不会改变时间复杂度。但是,您可能还想重载移动构造函数,这是另一回事:

B::B(B&& other)
  : beta(std::move(other.beta)),
    vec(std::move(other.vec))
{
    for (auto it = vec.begin(); it != vec.end(); ++it) {
        it->beta = &beta;
    }
}

这现在将时间复杂度从可能恒定变为可能线性。

注意:“指向成员变量的指针”的含义与指向对象内部变量的指针不同,但在这里两者都可能没有多大用处。如果你有一个指向成员的指针,你可以像这样声明/定义它:

VectorXd B::* member_ptr = &B::beta;

您可以在 B 类型的特定实例 b 上使用它,例如:

VectorXd val = b.*member_ptr;

。 如果你按照我上面展示的方式定义member_ptr,那么这行就意味着:

VectorXd val = b.beta;

.

【讨论】:

  • B类确实没有正确初始化C类中的指针。但是在解决方案上,您建议我如何更改C类构造函数和C类成员函数?我添加了 // ???在可能需要更改的代码中..
  • 不,我认为 C 类已正确实例化。只是B类的成员变量vec没有在B类的构造函数中实例化,需要在初始化列表中添加vec()。
  • 我不明白为什么这样可以解决问题?例如,如果我更改代码,使 B 类按值将 beta 向量传递给 C 类,而 C 类将 beta 存储为成员变量而不是指针,则 beta 值将正确打印。问题是更新 B 类中的 beta 向量不会影响 PrintBetas() 成员函数的输出。您能否提供正确初始化 B 类的 vec 成员的语法?谢谢!
  • 你有这行:B( VectorXd beta_IN, int nr_C ): beta( beta_IN ) {。进入:B( VectorXd beta_IN, int nr_C ): beta( beta_IN ), vec() {。您没有初始化 vec()。我认为通常会导致编译器警告,您可能应该打开它们。但是,我意识到还有另一个问题,即如果复制了一个 B,那么新 B 中的 Cs 仍将指向旧 B 中的 beta。我将尽快编辑我的答案。
  • 我尝试了您建议的解决方案,但没有奏效,即 PrintBetas() 函数仍然无法在屏幕上打印 VectorXd beta 值 nr_C 次。你是对的,你需要一个复制构造函数,但在我的例子中,类层次结构被初始化一次并且之后没有改变,因此我尽可能简单地保持这个例子。
猜你喜欢
  • 2022-10-25
  • 1970-01-01
  • 2021-05-18
  • 1970-01-01
  • 2018-03-24
  • 1970-01-01
  • 2021-12-18
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多