【问题标题】:How to best deal with C++ classes that need to have an object of self type?如何最好地处理需要具有自身类型对象的 C++ 类?
【发布时间】:2020-04-24 12:31:16
【问题描述】:

我是 C++ 初学者,在其他编程语言(即 Python、Javascript)方面有一定经验。 我有几个关于“递归”类的问题——在自己内部声明的类——在 C++ 中。

问题 1

对于具有构造函数的类,我知道在其内部声明它会导致其声明不完整,因此编译器将无法计算出其对象的大小。 到目前为止,我了解到一个类声明只能包含一个指向自我类型的指针一个自我类型的静态对象。 但是,我不明白这两种方法的好处是什么?我的目标是使用类似于树结构/网络的类,其中每个节点都存储其父节点和子节点!

问题 2

父节点和子节点都将使用类函数进行设置。如何在同一类的函数中声明自我类型?我是否也使用静态或指针?在这种情况下如何正确初始化?

example.cpp

#include "Point.hpp"

class Node {
    //Node parent; // ERROR

    // Option 1: Pointer
    Node * parent;

    // Option 2: Static
    static Node parent;

    vector<Node> children;

public:
    Node(float _x, float _y, float _z);
    void setChildren(/* some params */);

    float x, y, z;
};

example.hpp

Node::Node(float _x, float _y, float _z) {
    x = _x;
    y = _y;
    z = _z;
}

void Node::setChildren(/* some params */) {
    Node child1, child2; // ERROR: how to declare here?

    // do stuff with the parameters...

    child1 = {/*x1, y1, z1*/}; // ERROR: how to initialise?
    child2 = {/*x2, y2, z2*/}; // ERROR: how to initialise?
    children.push_back(child1);
    children.push_back(child2)

我希望有人能给我解释一下!我真的迷路了。

谢谢!非常感谢任何帮助。

【问题讨论】:

  • Node child1; 给出错误的唯一原因是因为您试图默认构造一个没有默认构造函数的对象
  • static 在这里不起作用。它将导致创建一个不与该类的任何特定对象关联的单个对象。这意味着您将只有一个父对象,无论您创建了 0 个、1 个还是多个其他对象。
  • class Node { Node parent; }; 会无限大,因为每个parent 还包含一个parent
  • 一个数据成员占用了对象的空间。编译器可以计算出大小,它将是无限的。
  • 它甚至不可能是无限的,因为内层和外层的大小必须相同。想象一个用胶带封口的纸箱,在纸箱里面放着一个花瓶,还有另一个和第一个盒子一样大小的用胶带封口的纸箱。这没有意义。盒子里不能装和自己一样大的东西。

标签: c++ class oop


【解决方案1】:

您的声明和定义在错误的文件中。类声明应该在头文件(.hpp)中,函数/构造函数等定义应该在源文件(.cpp)中。您需要在源文件中包含头文件,如下所示:

example.hpp

#include "Point.hpp"

class Node {
    // Use Option 1: Pointer
    Node* parent = nullptr;

    list<Node> children;

public:
    Node(float _x, float _y, float _z);
    void setChildren(/* some params */);

    float x, y, z;
};

example.cpp

#include "example.hpp"

Node::Node(float _x, float _y, float _z) {
    x = _x;
    y = _y;
    z = _z;
}

void Node::setChildren(/* some params */) {
    Node child1 = {x1, y1, z1};
    Node child2 = {x2, y2, z2};

    // do stuff with the parameters...

    push_back(child1);
    push_back(child2);
}

设置父指针的一种方法是向Node 类添加一个新的push_back 函数,以便在将新子对象添加到children 列表之前/或之后将指针设置在新子对象上。

您还可以在 C++ 中像这样初始化 child1/2。

Node child1 = {x1, y1, z1};
Node child2 = {x2, y2, z2};

“但是,我不明白这两种方法的好处是什么?”

在 C++ 中,您的成员函数中始终都有 this 指针,这意味着不需要像在其他编程语言中那样使用 self 指针 this 是您的 self 指针。

另外,如果您正在计划我看到您正在计划的内容,为了使其工作,您不会希望将vector 用于children,因为vector 使用连续内存,这将无效一旦vector 的内部内存被调整大小(可能发生在push_back 和其他操作,即擦除/插入),所有指向它的指针/迭代器。这意味着在这种情况下,更容易做的是使用list 而不是vector。这样,在添加/删除新子代时,父后向指针不会失效(例如 push_back)。

请参阅 std::vector 和 std::list 的文档。

https://en.cppreference.com/w/cpp/container/vector https://en.cppreference.com/w/cpp/container/list

【讨论】:

  • 哦,我的错!我一定是换了上面的标题。对不起!我是否像这样在新的子对象上设置父指针:child1.parent = this?注意,关于孩子的初始化。谢谢!好的,我将直接研究向量与列表。我还有一个问题是,为什么这适用于Node * parent;?我的意思是,使用指针在 Node 类中声明 Node 是如何工作的?这里发生了什么事?感谢您的精心回复!
  • 是的,您在子类中设置了父指针,您的父指针也应默认为nullptr(答案已编辑)。指针和引用不需要初始化完整的对象,因此可以在还不是完整类型的class/struct 中声明。这也适用于vector&lt;Node&gt;list&lt;Node&gt;,因为这些对象只包含指向Node 的指针,它们也不需要完整的类型。但是,如果他们这样做了,那将是一个错误。
  • 非常感谢!现在一切都像魅力一样,我学到了很多! :)
猜你喜欢
  • 1970-01-01
  • 2020-08-15
  • 2023-04-11
  • 1970-01-01
  • 2021-05-08
  • 1970-01-01
  • 2021-10-16
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多