简体   繁体   English

编译器在哪里存储C ++类的方法?

[英]Where does the compiler store methods for C++ classes?

This is more a curiosity than anything else... 这更像是一种好奇心......

Suppose I have a C++ class Kitty as follows: 假设我有一个C ++类Kitty如下:

class Kitty
{
    void Meow()
    {
        //Do stuff
    }
}

Does the compiler place the code for Meow() in every instance of Kitty? 编译器是否将Meow()的代码放在Kitty的每个实例中?

Obviously repeating the same code everywhere requires more memory. 显然,在任何地方重复相同的代码需要更多的内存。 But on the other hand, branching to a relative location in nearby memory requires fewer assembly instructions than branching to an absolute location in memory on modern processors, so this is potentially faster. 但另一方面,分支到附近内存中的相对位置需要更少的汇编指令,而不是分支到现代处理器的内存中的绝对位置,因此这可能更快。

I suppose this is an implementation detail, so different compilers may perform differently. 我想这是一个实现细节,因此不同的编译器可能会有不同的表现。

Keep in mind, I'm not considering static or virtual methods here. 请记住,我不是在考虑静态或虚拟方法。

In the usual implementation, there's only one copy of any given function. 在通常的实现中,任何给定函数只有一个副本。 The association between the code and the data for a given object instance is established by passing a hidden parameter (referred to a this in the function) that's a pointer to the object instance (and its data). 代码与给定对象实例的数据之间的关联是通过传递一个隐藏参数(在函数中称为this )来建立的,该参数是指向对象实例(及其数据)的指针。

For virtual functions, things get a bit more convoluted: each class gets a vtable that holds a set of pointers to the virtual functions, and each object gets a pointer to the vtable for its class. 对于虚函数,事情变得更复杂:每个类都获得一个vtable,它包含一组指向虚函数的指针,每个对象都获得一个指向其类的vtable的指针。 The virtual functions are invoked by finding the vtable pointer, looking at the correct offset, and invoking the function pointed to by that pointer. 通过查找vtable指针,查看正确的偏移量以及调用该指针指向的函数来调用虚函数。

我相信实例方法的标准方法是像任何静态方法一样实现,只执行一次,但是将this指针传递到特定寄存器或堆栈上以执行调用。

No, this is not the way it is done. 不,这不是它的方式。
Methods that are not virtual are exactly the same as any other function but with an additional argument for the this pointer. virtual方法与任何其他函数完全相同,但具有this指针的附加参数。

Methods that are virtual are invoked using a v-table . 使用v表调用 virtual方法。 the v-table is a list of function pointers which are stored next to the objects data. v表是一个函数指针列表,它存储在对象数据旁边。 In a sense, this is closer to what you describe but still, the body of the function is always the same for all instances of the object. 从某种意义上说,这更接近你描述的内容,但是,对于函数的所有实例,函数的主体总是相同的。
This can be demonstrated if you have a static variable in the method. 如果方法中有static变量,则可以证明这一点。 The static variable is going to be the same for methods invoked from different instances. 对于从不同实例调用的方法,静态变量将是相同的。

Because you have the definition of Meow inside the class definition, Meow is implicitly inline. 因为你在类定义中有Meow的定义,所以Meow是隐式内联的。

inline is a hint to the compiler to replace the call with the actual contents of the function. inline是一个提示编译器用函数的实际内容替换调用。 But it is only a hint - the compiler may choose to ignore the hint. 但它只是一个提示 - 编译器可能会选择忽略提示。

If the compiler abides by the hint, each call will be replaced with the function contents. 如果编译器遵守提示,则每个调用都将替换为函数内容。 That means the compiler will generate the code each time Meow is called instead of generating a function call. 这意味着编译器将在每次调用Meow时生成代码,而不是生成函数调用。

If the compiler ignores the hint, the compiler/linker will arrange for there to be a single version that all calls will be directed to (because it is inline, a classic strategy is that every translation unit that uses the function will get a separate copy with instructions to the linker to keep only one version). 如果编译器忽略了提示,编译器/链接器将安排将所有调用定向到的单个版本(因为它是内联的,一个经典策略是每个使用该函数的翻译单元将获得一个单独的副本指示链接器只保留一个版本)。

Finally, let's move into explanations where the function is not inline. 最后,让我们进入功能不内联的解释。 In this case, it is required for the coder to make sure the definition appears in exactly one translation unit and all calls will be sent to this one version. 在这种情况下,编码人员需要确保定义只出现在一个翻译单元中,并且所有呼叫都将被发送到这个版本。

No, the compiler only generates the code for Meow once and each Kitty instance uses that provided the member was compiled out-of-line. 不,编译器只为Meow生成一次代码,并且每个Kitty实例都使用该代码,只要该成员是在线外编译的。 If the compiler is able to and chooses to inline the function then it gets duplicated at each point of use (rather than with every instance of a Kitty ). 如果编译器能够并选择内联函数,则它在每个使用点(而不是每个Kitty实例)都会重复。

The compiler creates an entry for every class (not object) inside its own data structure. 编译器为其自己的数据结构中的每个类(而不是对象)创建一个条目。 This entry for the class contains pointers to the methods for that class. 该类的此条目包含指向该类的方法的指针。

An object is represented in memory as a pointer to the parent class and a collection of its instance fields (since these are different for every object.) Then when a method is called, the object follows the pointer to its parent which then follows the pointer to the appropriate method. 对象在内存中表示为指向父类的指针及其实例字段的集合(因为它们对于每个对象都是不同的。)然后,当调用方法时,对象跟随指向其父对象的指针,然后指向指针适当的方法。 A pointer to the object is also supplied to the method, which acts as the this pointer. 指向该对象的指针也提供给该方法,该方法充当该指针。

Virtual methods are a little more complicated, but they are done in a similar way. 虚拟方法稍微复杂一些,但它们以类似的方式完成。

If you want to know more, see if you can take a programming languages class. 如果您想了解更多信息,请查看是否可以参加编程语言课程。

Here's a poor attempt at ASCII art to explain it: 这是一个很难尝试ASCII艺术来解释它:

 obj                        class
+------------+            +----------+
| ptrToClass |----------->| method1  | ----------> toSomewhere(ptrToObj)
|------------|            |----------|
| field1     |            | method2  | ----------> toSomewhereElse(ptrToObj)
+------------+            +----------+

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 C ++编译器从哪里开始? - Where does the C++ compiler start? 英特尔 C++ 编译器将 vptr(指向虚拟 function 表的指针)存储在 Object 中的什么位置? - Where does Intel C++ Compiler store the vptr ( pointer to virtual function table ) in an Object? 使用 std::function 存储继承类的方法 c++ - Using std::function to store methods of inherited classes c++ c++ protobuf——我生成的类中的所有方法在哪里? - c++ protobuf -- where are all the methods in my generated classes? 在C ++ 2017中将const转换为非const指针并对其进行修改时,编译器将两个值都存储在哪里? - When casting a const to a non-const pointer in C++ 2017 and modifying it, where does the compiler store both values? 我的C ++编译器在哪里解析我的#includes? - Where does my C++ compiler look to resolve my #includes? 类中的方法是否使用现代 c++ 编译器内联的“奇怪重复的模板模式” - Are methods in classes using the 'Curiously Recurring Template Pattern' inlined by a modern c++ compiler C ++中的模板类和方法 - Template Classes and methods in C++ C ++编译器最大类数 - C++ compiler maximum number of classes 编译器在哪里存储常量数组? - Where does compiler store constant arrays?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM