C++ 使用合成类中计算的数据构造成员类

C++ 使用合成类中计算的数据构造成员类,c++,C++,我有一个类Itch,它是类Scratch的成员。我想在Scratch构造函数中进行一些计算,并将这些计算的结果传递给实例化Itch对象。我的最佳猜测如下,但这会返回垃圾: #include <iostream> class Itch { public: int N; Itch(int n) {N = n;} }; class Scratch { private: int N; public: Itch it; Scratch(int n); }; Scrat

我有一个类
Itch
,它是类
Scratch
的成员。我想在
Scratch
构造函数中进行一些计算,并将这些计算的结果传递给实例化
Itch
对象。我的最佳猜测如下,但这会返回垃圾:

#include <iostream>

class Itch {
public:
  int N;
  Itch(int n) {N = n;}
};

class Scratch {
private:
  int N;
public:
  Itch it;
  Scratch(int n);
};

Scratch::Scratch(int n) : it(N)  // here is where I want to use new data
{
  // do some silly things
  int temp = 5;
  temp += n + 45;
  N = temp - 1;
}

int main() {
  int n = 1;
  Scratch sc(n);

  std::cout << sc.it.N << "\n";
}
#包括
班痒{
公众:
int N;
痒(int n){n=n;}
};
课堂擦伤{
私人:
int N;
公众:
搔痒;
划痕(int n);
};
Scratch::Scratch(int n):it(n)//这里是我想要使用新数据的地方
{
//做些傻事
内部温度=5;
温度+=n+45;
N=温度-1;
}
int main(){
int n=1;
划痕sc(n);

std::cout初始值设定项列表中的内容发生在构造函数代码中的内容之前。因此,您不能使用构造函数中的代码影响初始值设定项列表中的任何内容。您有几个选项

一种合理的方法是使用
Itch*
成员而不是
Itch
,并在其准备就绪时对其进行初始化,例如:

class Scratch {
  ...
  Itch *it;
  ...
};

Scratch::Scratch(int n) : it(NULL)
{
  // do some silly things
  int temp = 5;
  temp += n + 45;
  N = temp - 1;
  it = new Itch(N); // <- now you have enough info to instantiate an Itch
}
另一种合理的方法是将
n
传递给
Itch
构造函数,让它在那里进行计算,而不是在
Scratch
中,甚至可能允许
Itch
确定
n
,例如:

class Itch {
private:
   int N;
public:
   Itch (int n);
   int getN () const { return N; }
}

Itch::Itch (int n) {
  // do some silly things
  int temp = 5;
  temp += n + 45;
  N = temp - 1;
}

Scratch::Scratch (int n) : it(n) {
  // you can either remove Scratch::N altogether, or I suppose do:
  N = it.getN();
  // ... do whatever makes sense, try not to have redundant data.
  // (also ask yourself if Scratch even *needs* to know N, or at
  // least if it can just use it.getN() everywhere instead of
  // keeping its own copy.)
}
另一种方法(IMO有点奇怪,但在某些情况下仍有可能)是使用静态函数(成员或非成员),从
N
计算
N
,您可以在初始值设定项列表中使用该函数,例如:

static int doSillyThings (int n) {
  int temp = 5;
  temp += n + 45;
  return temp - 1;
}

Scratch::Scratch(int n) : N(doSillyThings(n)), it(N)
{
}
选择最干净、最易维护和易于阅读的代码。就个人而言,我更喜欢第一个,
Itch*
选项,因为它具有逻辑意义,而且非常清楚:您进行必要的计算来初始化
Itch
,然后初始化它

你应该考虑一下你的代码。如果
Scratch
N
总是等于
it.N
,那么你真的需要这两个
N

还有其他选择(包括完全重构代码,这样您就不必拥有
Scratch
Itch
成员,或者不必拥有
it
依赖于对
Scratch
的构造函数参数进行的额外计算,但这实际上取决于具体情况),但希望这能给你一点启发



顺便说一下,代码返回垃圾的原因是,
N
在传递给
Itch
构造函数时是垃圾。在初始化它之前,它是未初始化的,在
it(N)处
是指您还没有初始化
N

太好了!我将使用第一种方法。不过有一个问题:我必须仍然拥有
它(NULL)
在初始化列表中?我记得,如果成员对象的构造函数需要参数,那么它必须在初始化列表中构造,因此我认为这与此要求一致?@bcf您不必拥有
它(NULL)
在列表中。它只是初始化指向NULL的指针,而不是随机垃圾,但您正在设置指向构造函数中某个内容的指针。我之所以将其放在那里,是因为我喜欢确保所有成员在任何时候都有可预测的定义良好的值(我相信指针应该始终有效或为NULL);在这种情况下,这意味着在构造函数代码中的任何一点上,您都可以通过检查其值是否为NULL来判断
它是否已设置为
new Itch()
。但实际上
auto_ptr
也可以处理此问题,可能是更好的选择。@bcf(如果抛出异常,保持指针为NULL或有效也有助于清除异常,但同样,
auto_ptr
)。请注意
it(NULL)
Itch
构造函数无关!!这不是
Itch
构造函数。它只是将指针
It
设置为
NULL
,稍后将其设置为
新的Itch(…)
static int doSillyThings (int n) {
  int temp = 5;
  temp += n + 45;
  return temp - 1;
}

Scratch::Scratch(int n) : N(doSillyThings(n)), it(N)
{
}