类中的“不完整类型”,该类本身具有相同类型的成员

时间:2021-03-03 16:46:20

I have a class that should have a private member of the same class, something like:

我有一个类应该有一个相同类的私人成员,比如:

class A {
    private:
        A member;
}

But it tells me that member is an incomplete type. Why? It doesn't tell me incomplete type if I use a pointer, but I'd rather not use a pointer. Any help is appreciated

但是它告诉我成员是不完整的类型。为什么?如果我使用指针,它不会告诉我不完整类型,但我宁愿不使用指针。任何帮助都是赞赏

8 个解决方案

#1


37  

At the time you declare your member, you are still defining the A class, so the type A is still undefined.

在声明成员时,仍然定义了A类,所以类型A仍然没有定义。

However, when you write A*, the compiler already knows that A stands for a class name, and so the type "pointer to A" is defined. That's why you can embed a pointer to the type your are defining.

但是,当您编写一个*时,编译器已经知道A代表一个类名,因此定义了“指向A的指针”类型。这就是为什么您可以嵌入到您正在定义的类型的指针。

The same logic applies also for other types, so if you just write:

同样的逻辑也适用于其他类型,所以如果你只写:

class Foo;

You declare the class Foo, but you never define it. You can write:

您声明了Foo类,但是从来没有定义它。你可以写:

Foo* foo;

But not:

而不是:

Foo foo;

On another hand, what memory structure would you expect for your type A if the compiler allowed a recursive definition ?

另一方面,如果编译器允许递归定义,那么您希望A类型的内存结构是什么?

However, its sometimes logically valid to have a type that somehow refer to another instance of the same type. People usually use pointers for that or even better: smart pointers (like boost::shared_ptr) to avoid having to deal with manual deletion.

但是,有时具有引用相同类型的另一个实例的类型在逻辑上是有效的。人们通常会为此使用指针,甚至更好:智能指针(比如boost::shared_ptr),以避免不得不处理手工删除。

Something like:

喜欢的东西:

class A
{
  private:
    boost::shared_ptr<A> member;
};

#2


22  

This is a working example of what you are trying to achieve:

这是一个你正在努力实现的工作例子:

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

Happy Stack Overflow!

Stack Overflow快乐!

#3


5  

A is "incomplete" until the end of its definition (though this does not include the bodies of member functions).

A在其定义结束之前是“不完整的”(尽管这并不包括成员函数的主体)。

One of the reasons for this is that, until the definition ends, there is no way to know how large A is (which depends on the sum of sizes of members, plus a few other things). Your code is a great example of that: your type A is defined by the size of type A.

其中一个原因是,在定义结束之前,没有办法知道A有多大(这取决于成员的大小和其他一些东西)。您的代码就是一个很好的例子:类型a由类型a的大小定义。

Clearly, an object of type A may not contain a member object that is also of type A.

显然,类型A的对象可能不包含同样类型A的成员对象。

You'll have to store a pointer or a reference; wanting to store either is possibly suspect.

必须存储指针或引用;想要存储其中任何一个都可能是可疑的。

#4


2  

You cannot include A within A. If you were able to do that, and you declared, for example, A a;, you would need to refer to a.member.member.member... infinitely. You don't have that much RAM available.

你不能在A中包含A,如果你能做到这一点,并且你声明了A;,你就需要参考a.c rew。member.member…无限。你没有那么多RAM。

#5


1  

How can an instance of class A also contain another instance of class A?

类A的实例如何也包含类A的另一个实例?

It can hold a pointer to A if you want.

如果你愿意,它可以保存指向a的指针。

#6


1  

This type of error occurs when you try to use a class that has not yet been fully DEFINED.

当您尝试使用一个尚未完全定义的类时,就会发生这种类型的错误。

Try to use A* member instead.

尝试使用*成员代替。

#7


0  

The problem happens when the compiler comes across an object of A in code. The compiler will rub its hand and set out make an object of A. While doing that it will see that A has a member which is again of type A. So for completing the instantiation of A it now has to instantiate another A ,and in doing so it has to instantiate another A and so forth. You can see it will end up in a recursion with no bound. Hence this is not allowed. Compiler makes sure it knows all types and memory requirement of all members before it starts instantiating an object of a class.

当编译器遇到in代码中的A对象时,就会出现问题。编译器会搓手,使一个对象出发的A。虽然这样做将看到一个又一个成员完成实例化的类型A .所以现在必须实例化另一个,这样它实例化另一个等等。你可以看到它会以一个没有边界的递归结束。因此这是不允许的。编译器确保在开始实例化类的对象之前知道所有成员的所有类型和内存需求。

#8


0  

A simple way to understand the reason behind class A being incomplete is to try to look at it from compiler's perspective.

理解类A不完整的原因的一种简单方法是尝试从编译器的角度来看它。

Among other things, the compiler must be able to compute the size of A object. Knowing the size is a very basic requirement that shows up in many contexts, such as allocating space in automatic memory, calling operator new, and evaluating sizeof(A). However, computing the size of A requires knowing the size of A, because a is a member of A. This leads to infinite recursion.

此外,编译器必须能够计算对象的大小。知道大小是在许多上下文中出现的一个非常基本的需求,例如在自动内存中分配空间、调用操作符new和评估sizeof(a)。然而,计算A的大小需要知道A的大小,因为A是A的成员,这导致了无限递归。

Compiler's way of dealing with this problem is to consider A incomplete until its definition is fully known. You are allowed to declare pointers and references to incomplete class, but you are not allowed to declare values.

编译器处理这个问题的方法是考虑一个不完整的直到它的定义被完全知道。允许声明指向不完整类的指针和引用,但不允许声明值。

#1


37  

At the time you declare your member, you are still defining the A class, so the type A is still undefined.

在声明成员时,仍然定义了A类,所以类型A仍然没有定义。

However, when you write A*, the compiler already knows that A stands for a class name, and so the type "pointer to A" is defined. That's why you can embed a pointer to the type your are defining.

但是,当您编写一个*时,编译器已经知道A代表一个类名,因此定义了“指向A的指针”类型。这就是为什么您可以嵌入到您正在定义的类型的指针。

The same logic applies also for other types, so if you just write:

同样的逻辑也适用于其他类型,所以如果你只写:

class Foo;

You declare the class Foo, but you never define it. You can write:

您声明了Foo类,但是从来没有定义它。你可以写:

Foo* foo;

But not:

而不是:

Foo foo;

On another hand, what memory structure would you expect for your type A if the compiler allowed a recursive definition ?

另一方面,如果编译器允许递归定义,那么您希望A类型的内存结构是什么?

However, its sometimes logically valid to have a type that somehow refer to another instance of the same type. People usually use pointers for that or even better: smart pointers (like boost::shared_ptr) to avoid having to deal with manual deletion.

但是,有时具有引用相同类型的另一个实例的类型在逻辑上是有效的。人们通常会为此使用指针,甚至更好:智能指针(比如boost::shared_ptr),以避免不得不处理手工删除。

Something like:

喜欢的东西:

class A
{
  private:
    boost::shared_ptr<A> member;
};

#2


22  

This is a working example of what you are trying to achieve:

这是一个你正在努力实现的工作例子:

class A {
public:
    A() : a(new A()) {}
    ~A() { delete a; a = nullptr; }
private:
    A* a;
};

A a;

Happy Stack Overflow!

Stack Overflow快乐!

#3


5  

A is "incomplete" until the end of its definition (though this does not include the bodies of member functions).

A在其定义结束之前是“不完整的”(尽管这并不包括成员函数的主体)。

One of the reasons for this is that, until the definition ends, there is no way to know how large A is (which depends on the sum of sizes of members, plus a few other things). Your code is a great example of that: your type A is defined by the size of type A.

其中一个原因是,在定义结束之前,没有办法知道A有多大(这取决于成员的大小和其他一些东西)。您的代码就是一个很好的例子:类型a由类型a的大小定义。

Clearly, an object of type A may not contain a member object that is also of type A.

显然,类型A的对象可能不包含同样类型A的成员对象。

You'll have to store a pointer or a reference; wanting to store either is possibly suspect.

必须存储指针或引用;想要存储其中任何一个都可能是可疑的。

#4


2  

You cannot include A within A. If you were able to do that, and you declared, for example, A a;, you would need to refer to a.member.member.member... infinitely. You don't have that much RAM available.

你不能在A中包含A,如果你能做到这一点,并且你声明了A;,你就需要参考a.c rew。member.member…无限。你没有那么多RAM。

#5


1  

How can an instance of class A also contain another instance of class A?

类A的实例如何也包含类A的另一个实例?

It can hold a pointer to A if you want.

如果你愿意,它可以保存指向a的指针。

#6


1  

This type of error occurs when you try to use a class that has not yet been fully DEFINED.

当您尝试使用一个尚未完全定义的类时,就会发生这种类型的错误。

Try to use A* member instead.

尝试使用*成员代替。

#7


0  

The problem happens when the compiler comes across an object of A in code. The compiler will rub its hand and set out make an object of A. While doing that it will see that A has a member which is again of type A. So for completing the instantiation of A it now has to instantiate another A ,and in doing so it has to instantiate another A and so forth. You can see it will end up in a recursion with no bound. Hence this is not allowed. Compiler makes sure it knows all types and memory requirement of all members before it starts instantiating an object of a class.

当编译器遇到in代码中的A对象时,就会出现问题。编译器会搓手,使一个对象出发的A。虽然这样做将看到一个又一个成员完成实例化的类型A .所以现在必须实例化另一个,这样它实例化另一个等等。你可以看到它会以一个没有边界的递归结束。因此这是不允许的。编译器确保在开始实例化类的对象之前知道所有成员的所有类型和内存需求。

#8


0  

A simple way to understand the reason behind class A being incomplete is to try to look at it from compiler's perspective.

理解类A不完整的原因的一种简单方法是尝试从编译器的角度来看它。

Among other things, the compiler must be able to compute the size of A object. Knowing the size is a very basic requirement that shows up in many contexts, such as allocating space in automatic memory, calling operator new, and evaluating sizeof(A). However, computing the size of A requires knowing the size of A, because a is a member of A. This leads to infinite recursion.

此外,编译器必须能够计算对象的大小。知道大小是在许多上下文中出现的一个非常基本的需求,例如在自动内存中分配空间、调用操作符new和评估sizeof(a)。然而,计算A的大小需要知道A的大小,因为A是A的成员,这导致了无限递归。

Compiler's way of dealing with this problem is to consider A incomplete until its definition is fully known. You are allowed to declare pointers and references to incomplete class, but you are not allowed to declare values.

编译器处理这个问题的方法是考虑一个不完整的直到它的定义被完全知道。允许声明指向不完整类的指针和引用,但不允许声明值。