C++ 派生到基类转换

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3694180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-28 13:29:13  来源:igfitidea点击:

Derived to base class conversion

c++

提问by user963241

How does the conversion between derived and base class internally occurs and how does compiler knows or does it store the size of object?

派生类和基类之间的转换如何在内部发生,编译器如何知道或存储对象的大小?

For example in the following:

例如在下面:

class A
{
public:
 A():x(2){};
private:
 int x;
};

class B : public A
{
public:
 B():A(),y(5){};
private:
 int y;
};

class C : public B
{
public:
 C():B(),z(9){};
private:
 int z;
};

int main()
{
   C *CObj = new C;
   B *pB = static_cast<B*>(CObj);
   delete CObj;
}

Edit:It must have been this:

编辑:它一定是这样的:

B BObj = static_cast<B>(*CObj);

回答by AnT

You don't have any "derived to base" conversion in your code. What you have in your code is a pointer-to-derived to pointer-to-base conversion. (This conversion does not require any explicit cast, BTW)

您的代码中没有任何“派生到基础”的转换。您在代码中拥有的是指向派生指针指向指针的转换。(此转换不需要任何显式转换,顺便说一句)

B *pB = CObj; // no need for the cast

In order to perform the pointer conversion, there's no need to know the size of the object. So, it is not clear where your reference to "size of the object" comes from.

为了执行指针转换,不需要知道对象的大小。因此,不清楚您对“对象大小”的引用来自何处。

In fact, in the typical implementation the above conversion for single-inheritance hierarchy of non-polymorphic classes is purely conceptual. I.e. the compiler does not do anything besides simply copying the numerical value of the derived pointer into the base pointer. No extra information is needed to perform this operation. No size, no nothing.

事实上,在典型的实现中,非多态类的单继承层次结构的上述转换纯粹是概念上的。即编译器除了简单地将派生指针的数值复制到基指针之外,不做任何事情。执行此操作不需要额外的信息。没有大小,什么都没有。

In more complicated situations (like multiple inheritance), the compiler might indeed have to generate code that would adjust the value of the pointer. And it will indeed need to know the sizes of the objects involved. But the sizes involved are always compile-time ones, i.e. they are compile-time constants, meaning that the compiler does immediately know them.

在更复杂的情况下(如多重继承),编译器可能确实需要生成代码来调整指针的值。它确实需要知道所涉及对象的大小。但是涉及的大小总是编译时的,即它们是编译时常量,这意味着编译器会立即知道它们。

In even more complicated cases, like virtual inheritance, this conversion is normally supported by run-time structures implicitly built into the object, which will include everything deemed necessary. Run-time size of the object might be included as well, if the implementation chooses to do so.

在更复杂的情况下,如虚拟继承,这种转换通常由隐含在对象中的运行时结构支持,其中包括所有被认为必要的内容。如果实现选择这样做,也可能包括对象的运行时大小。

回答by Oliver Charlesworth

Note that you don't need the static_casthere; it's perfectly legal to "up-cast" a pointer-to-derived-class to a pointer-to-parent-class.

请注意,您不需要static_cast此处;将指向派生类的指针“向上转换”为指向父类的指针是完全合法的。

In this example, there is no conversion going on. The pointer value stays the same (i.e. under the hood, CObjand pBpoint at the same memory, though things get more complex with multiple inheritance). The compiler organises the members of Band Cobjects in memory so that everything just works. As we're dealing with pointers, the size of the object doesn't matter (that was only relevant when you created a new C).

在此示例中,没有进行任何转换。指针值保持不变(即在引擎盖下,CObjpB指向相同的内存,尽管多重继承使事情变得更加复杂)。编译器在内存中组织BC对象的成员,以便一切正常。当我们处理指针时,对象的大小并不重要(这仅在您创建 a 时才相关new C)。

If you had any virtual methods, then we could talk about vtables and vptrs (http://en.wikipedia.org/wiki/Vtable).

如果您有任何虚拟方法,那么我们可以讨论 vtables 和 vptrs ( http://en.wikipedia.org/wiki/Vtable)。

回答by Chubsdad

A derived class object has base class subobjects. Specifically the Standard says in 10.3

派生类对象具有基类子对象。特别是标准在 10.3 中说

"The order in which the base class subobjects are allocated in the most derived object (1.8) is unspecified"

“基类子对象在派生最多的对象 (1.8) 中分配的顺序未指定”

This means that even though many a times, the base subobject could be right at the beginning of the derived object, it is not necessary. Hence the conversion from Derived* to Base* is completely unspecified and is probably left as a degree of latitude to compiler developers.

这意味着,即使很多时候,基础子对象可能正好位于派生对象的开头,但这不是必需的。因此,从 Derived* 到 Base* 的转换是完全未指定的,并且可能留给编译器开发人员一定程度的自由。

I would say that it is important to know the rules of the language and the reason behind the same, rather than worry about how compiler implements them. As an example, I have seen far too many discussions on VTABLE and VPTR which is a compiler specific implementation to achieve dynamic binding. Instead it helps to know about the concept of 'unique final overrider' that is enough to understand the concept of virtual functions and dynamic binding. The point is to focus on 'what' rather than 'how', because 'how' most of the times is not required. I say most of the times because in some cases it helps. An example is to understand the concept of 'pointer to members'. It helps to know that it is usually implemented in some form of 'offset' rather than being a regular pointer.

我会说重要的是了解语言的规则及其背后的原因,而不是担心编译器如何实现它们。例如,我已经看到太多关于 VTABLE 和 VPTR 的讨论,它们是实现动态绑定的编译器特定实现。相反,它有助于了解“唯一最终覆盖”的概念,这足以理解虚函数和动态绑定的概念。重点是关注“什么”而不是“如何”,因为大多数时候不需要“如何”。大多数时候我会说,因为在某些情况下它会有所帮助。一个例子是理解“成员指针”的概念。知道它通常以某种形式的“偏移量”而不是常规指针来实现是有帮助的。

回答by Martin York

How does the conversion between derived and base class internally occurs

派生类和基类之间的转换内部是如何发生的

Implementation defined.
Imposable to answer unless you tell us which compiler you are using.
But generally not worth knowing or worrying about (unless you are writing a compiler).

实现定义。
除非您告诉我们您使用的是哪种编译器,否则无法回答。
但通常不值得了解或担心(除非您正在编写编译器)。

and how does compiler knows [editor] size of the object

以及编译器如何知道 [编辑器] 对象的大小

The compiler knows the size (It has worked out the size of C during compilation).

编译器知道大小(它在编译期间计算出 C 的大小)。

or does it store the size of object?

还是存储对象的大小?

The object does not need to know the size and thus it is not stored as part of the class.
The runtime memory management (used via new) may need to know (but it is implementation defined) so that it can correctly release the memory (but anything it stores will not be stroed in the object).

对象不需要知道大小,因此它不作为类的一部分存储。
运行时内存管理(通过 new 使用)可能需要知道(但它是实现定义的),以便它可以正确释放内存(但它存储的任何内容都不会在对象中被 stroed)。

回答by BatchyX

If you have ever done any C, the answer would come from itself.

如果你曾经做过任何 C,答案就会来自它本身。

A memory allocator doesn't care at all about what it is storing. It just have to know what memory ranges has been allocated. It doesn't see the difference between a C and an int[4]. It just have to know how to free the memory range that starts at the given pointer.

内存分配器根本不关心它存储的是什么。它只需要知道分配了哪些内存范围。它看不到 C 和 int[4] 之间的区别。它只需要知道如何释放从给定指针开始的内存范围。