在这种情况下如何利用指针

时间:2018-12-10 23:50:38

标签: c++ pointers

在以下.h中:

class First {
  private:
    int integer;

  public:
    First(int value);
};

class Second {
  private:
    First firstClass;

  public:
    Second(First first);
};

和.cpp:

#include "FileAbove.h"

First::First(int value) {
  integer = value;
}

Second::Second(First first) {
  firstClass = first;
}

代码...我正在尝试在第二堂课内学习第一堂课。并得到一个错误。
请注意,如果类First没有构造函数,则不会出现错误。为什么呢?
以及如何使它运行(使用构造函数)?
作为刚接触C ++的C#书呆子,我知道我需要使用某种指针,并且希望能获得一些帮助:)
错误:没有匹配的函数来调用“ First :: First()”

2 个答案:

答案 0 :(得分:0)

如果First具有用户声明的转换构造函数,则它将没有隐式生成的默认构造函数,因此First将无法默认构造。

您用于类Second的转换构造函数没有成员firstClass的成员初始化程序,该成员也没有默认的成员初始化程序,因此该成员将由该构造函数默认初始化。但是由于First无法默认构造,因此程序格式错误。

如果First没有转换的构造函数,那么它确实具有隐式生成的默认构造函数,并且不再存在矛盾。

解决方案a:通过定义默认构造函数使First默认构造为可构造。解决方案b:使用成员初始化程序初始化firstClass。

解决方案b可能更好,因为首先默认构造一个成员只是立即从构造函数参数中对其进行复制分配是没有意义的。


  

在这种情况下如何利用指针

在这种情况下不需要指针。

答案 1 :(得分:0)

必须在进入构造函数的主体之前构造所有类成员变量。这意味着

Second::Second(First first) 
{ // firstClass must have been constructed before here
    firstClass = first;
}

firstClass必须已经构造好才能进行作业。由于它没有默认构造函数,因此无法自动构造。您必须使用Member Initializer List

Second::Second(First first): firstClass(42) // don't care about the value because 
                                            // we're about to write over it.
{
    firstClass = first;
}

但这有点傻。 Second包含First的副本。两者之间没有联系。询问者说他们想让Second引用First。有两种方法可以做到:指针和引用。

我们将从参考开始,因为它通常是更好的选择(但在这种情况下可能不是)。为什么它是更好的选择,将在任何可靠的C ++编程文本中深入讨论。如果您没有可靠的编程文字,请节省大量时间并立即获取。

class First {
  private:
    int integer;

  public:
    First(int value);
};

class Second {
  private:
    First & firstClass; // is a reference

  public:
    Second(First &first); // accepts a reference otherwise what's the point?
};

First::First(int value): integer(value) {
    // done' save must with the initializer list here, but it's generally best to 
    // keep everything the same. That way irregularity is probably a bug and 
    // irregularities are easy to spot.
}

Second::Second(First & first): firstClass(first){
}

第二个现在引用第一个。引用是变量的别名,是变量的别名。通常,这是在幕后使用指针实现的,但并非必须如此。编译器可以对代码进行烹饪,以使firstClass及其源完全相同,并且firstClass不会占用内存。

需要注意的一件事,这里引用可能是一个错误的选择,是因为一旦初始化引用,就无法将其重定向为引用其他任何内容。这意味着您需要进行特殊处理才能分配Second,并且由于firstClass是唯一的数据成员,因此您永远无法真正对其进行更改。

由于Second并不真正持有First,因此必须确保First 它表示超过Second。如果没有,您就有所谓的悬挂参考。 Second无法知道它的引用已经消失,如果您尝试使用引用,则会发生不好的事情。

第二种方法是使用指针。

class First {
  private:
    int integer;

  public:
    First(int value);
};

class Second {
  private:
    First * firstClass; // is a pointer

  public:
    Second(First * first); // takes a pointer
};

First::First(int value) {
  integer = value;
}

Second::Second(First * first): firstClass(first){ 
}

int main()
{
    First f(42);
    Second s(&f); // must provide address
}

我添加了一个简单的main,因此您可以了解如何获取First的地址。指针可以重新指向,因此您可以分配给Second的这种变体(但通常要警惕OwnershipThe Rules of Three and Five

您还可以提供无效的指针或空指针。使用参考文献很难做到这一点,这也是为什么首选参考文献的重要原因。