虚函数, ->运算符, 继承如此混乱

virtual function, -> operator, inheritance SO CONFUSING

本文关键字:继承 运算符 混乱 gt 函数      更新时间:2023-10-16

好吧,这是一个简单的例子,让我很困惑…

class First { public: void Func() {cout<<"FirstFunc";} };
class Second : public First
    { public: void Func() {cout<<"SecondFunc";} };
class Third : public Second
    { public: void Func() {cout<<"ThirdFunc";} };
int main () {
   Third * thirdptr = new Third();
   Second * secondptr = thirdptr;
   First * firstptr = secondptr;
   firstptr->Func();  // prints out FirstFunc
   secondptr->Func();  // prints out SecondFunc
   thirdptr->Func();  // prints out ThirdFunc
   delete thirdptr;

这是虚函数

class First { public: virtual void Func() {cout<<"FirstFunc";} };
class Second : public First
    { public: virtual void Func() {cout<<"SecondFunc";} };
class Third : public Second
    { public: virtual void Func() {cout<<"ThirdFunc";} };
int main () {
   Third * thirdptr = new Third();
   Second * secondptr = thirdptr;
   First * firstptr = secondptr;
   firstptr->Func();  // prints out ThirdFunc
   secondptr->Func();  // prints out ThirdFunc
   thirdptr->Func();  // prints out ThirdFunc
   delete thirdptr;

好的,这是我的问题。

  1. 如何读取Third * thirdptr = new Third();New为int分配内存,当" New int"但我不知道我应该如何阅读新的第三();因为它是构造函数

  2. Second * secondptr = thirdptr;/First * firstptr = secondptr;这两个表述太令人困惑了。有人能用&操作符还是与地址操作符相关的简单词语?我理解了这个指针和继承的概念,但是这部分太混乱了。

  3. 我应该如何从第二个例子中得到结果?我在读的那本书上面写着

作为第一个例子//c++编译器对于指针的算术运算,做出一个决定//基于指针的类型,而不是指针实际指向的

作为第二个例子//虚拟函数:决定,不基于指针类型//根据指针实际指向的对象调用

这是翻译,所以可能不准确,但仍然无法理解。如果你能帮助我,我将非常感激!

  1. new Third()做两件事。首先为Third对象分配内存,然后调用Third对象的构造函数。您可以将语句分为两部分,new Third分配内存,()调用构造函数。

  2. Second * secondptr = thirdptr; / First * firstptr = secondptr;这三个变量都被赋值给同一个指针。假设thritptr等于100。那么在这些语句结束时,secondptrfirstptr都等于100。所有三个指针都指向内存中的同一地址。然而,由于它们是不同的类型,所以编译器对它们的解释不同

  3. 对于非虚函数,方法调用在编译时根据变量的类型进行解析。因此,在编译第一个代码时,firstptr的类型是First*,因此编译器生成对First::Func()的调用。对于虚函数,直到运行时才完全解析方法调用。编译器生成的代码将确定变量指向的实际类型并调用该函数。在第二个示例中,当程序运行时,firstpr->Func()首先确定firstptr确实指向Thrird对象,因此调用Third::Func()

回答你的第一个问题,new Third()在高层次上做着与new int相同的事情。正如您所说,new int将为int分配内存,并且左侧的指针将指向该内存。new Third()Third对象分配内存,并使用Third类的默认构造函数Third()来初始化它。

对于你的第二个问题,你正在创建三个指针,并将它们都指向同一个内存块。我相信,由于继承,可以隐式地将每个指针类型强制转换为更高的类型(隐式强制转换意味着没有显式指令,例如static_cast或c风格强制转换)。视觉:

----
|  | <-- Some block of memory.
----
A -> ---- <-- A* aptr = new A();
     |  |
     ----
A -> ----
B -> |  | <-- B* bptr = aptr;
     ----
A -> ----
B -> |  |
C -> ---- <-- C* cptr = bptr;

注意这三个指针是如何指向同一个内存块的。(还要注意,所有指针都指向内存的起始——完全相同的位置。很难在上面描述

关于你的第三个问题:

不是根据指针类型决定调用什么,而是根据指针类型决定调用什么指针实际上指向

意味着编译器将根据内存中对象的实际类型来决定调用函数的哪个实例,而不是根据指向内存的指针的类型。因此,在您的示例中,您创建了一个类型为Third的对象,并有三个指针指向它,类型为First, Second, Third。不管指针类型是什么,因为Func是虚拟的,所以Third版本的Func会被执行,因为内存中的对象类型是Third