虚函数与构造函数、析构函数

C++知识积累:构造函数与析构函数是否应为虚函数 目录 1 构造函数不能是虚函数 2 析构函数应当是虚函数 其他需要注意的地方 1 构造函数不能是虚函数 构造函数不能声明为虚函数。虚函数是需要通过对象中的虚表指针来找到虚函数表,然后再调用相应虚函数的。如果构造函数是虚函数,说明构造函数也是需要用虚表指针来调用的,但是这样一来就必须要先有虚表指针才行,而虚表指针又是存在于对象中,而对象本身又是需要先通过构造函数... 阅读详情

1、构造函数能不能是虚函数: 

1.1从存储空间角度

虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。

1.2从使用角度

虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有必要是虚函数。

1.3从作用

虚函数的作用在于通过父类的指针或者引用来调用它的时候能够变成调用子类的那个成员函数。而构造函数是在创建对象时自动调用的,不可能通过父类的指针或者引用去调用,因此也就规定构造函数不能是虚函数。
1.4
    vbtl
在构造函数调用后才建立,因而构造函数不可能成为虚函数。在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数);而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,也没有太大的必要成为虚函数

 

2、析构函数可以为虚函数,甚至是纯虚的
   
我们往往通过基类的指针来销毁对象。这时候如果析构函数不是虚函数,就不能正确识别对象类型从而不能正确调用析构函数。

class A
{
public:
    virtual ~A()=0;   //
纯虚析构函数

};
    
当一个类打算被用作其它类的基类时,它的析构函数必须是虚的。考虑下面的例子:
class A
{
public:
    A() { ptra_ = new char[10];}
    ~A() { delete[] ptra_;}        //
非虚析构函数
private:
    char * ptra_;
};
class B: public A
{
public:
    B() { ptrb_ = new char[20];}
    ~B() { delete[] ptrb_;}
private:
    char * ptrb_;
};
void foo()
{

    A * a = new B;
    delete a;
}
在这个例子中,程序也许不会象你想象的那样运行,在执行delete a的时候,实际上只有A::~A()被调用了,而B类的析构函数并没有被调用!这是否有点儿可怕?

      
如果将上面A::~A()改为virtual,就可以保证B::~B()也在delete a的时候被调用了。因此基类的析构函数都必须是virtual的。
      
纯虚的析构函数并没有什么作用,是虚的就够了。通常只有在希望将一个类变成抽象类(不能实例化的类),而这个类又没有合适的函数可以被纯虚化的时候,可以使用纯虚的析构函数来达到目的。

 

3、关于构造函数

编译器对每个包含虚函数的类创建一个表(称为VTABLE)。在VTABLE中,编译器放置特定类的虚函数地址。在每个带有虚函数的类中,编译器秘密地置一指针,称为vpointer(缩写为VPTR),指向这个对象的VTABLE。

当一个构造函数被调用时,它做的首要的事情之一是初始化它的VPTR。因此,它只能知道它是“当前”类的,而完全忽视这个对象后面是否还有继承者。当编译器为这个构造函数产生代码时,它是为这个类的构造函数产生代码--既不是为基类,也不是为它的派生类(因为类不知道谁继承它)。
   
所以它使用的VPTR必须是对于这个类的VTABLE。而且,只要它是最后的构造函数调用,那么在这个对象的生命期内,VPTR将保持被初始化为指向这个VTABLE。但如果接着还有一个更晚派生的构造函数被调用,这个构造函数又将设置VPTR指向它的 VTABLE,等.直到最后的构造函数结束。VPTR的状态是由被最后调用的构造函数确定的。这就是为什么构造函数调用是从基类到派生类顺序的另一个理由。

但是,当这一系列构造函数调用正发生时,每个构造函数都已经设置VPTR指向它自己的VTABLE。如果函数调用使用虚机制,它将只产生通过它自己的VTABLE的调用,而不是最后的VTABLE(所有构造函数被调用后才会有最后的VTABLE)。


 4
、  虚函数

是C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访问派生类定义的函数。假设我们有下面的类层次:
class A
{
public:
    virtual void foo() { cout << "A::foo() is called" << endl;}
};
class B: public A
{
public:
    virtual void foo() { cout << "B::foo() is called" << endl;}
};

那么,在使用的时候,
A * a = new B();
a->foo();       //
在这里,a虽然是指向A的指针,但是被调用的函数(foo)却是B的!
     
这个例子是虚函数的一个典型应用,通过这个例子,也许你就对虚函数有了一些概念。它虚就虚在所谓“推迟联编”或者“
动态联编”上,一个类函数的调用并不是在编译时刻被确定的,而是在运行时刻被确定的。由于编写代码的时候并不能确定被调用的是基类的函数还是哪个派生类的函数,所以被成为“虚”函数。
     
虚函数只能借助于指针或者引用来达到多态的效果,如果是下面这样的代码,则虽然是虚函数,但它不是多态的:
class A
{
public:
    virtual void foo();
};
class B: public A
{
    virtual void foo();
};
void bar()
{
    A a;
    a.foo();   // A::foo()
被调用
}
5
、 多态
    在了解了虚函数的意思之后,再考虑什么是多态就很容易了。仍然针对上面的类层次,但是使用的方法变的复杂了一些:

void bar(A * a)
{
    a->foo();  //
被调用的是A::foo() 还是B::foo()?
}
   
因为foo()是个虚函数,所以在bar这个函数中,只根据这段代码,无从确定这里被调用的是A::foo()还是B::foo(),但是可以肯定的说:如果a指向的是A类的实例,则A::foo()被调用,如果a指向的是B类的实例,则B::foo()被调用。
这种同一代码可以产生不同效果的特点,被称为“多态”。

5.1
多态有什么用?
       多态这么神奇,但是能用来做什么呢?这个命题我难以用一两句话概括,一般的C++
教程(或者其它面向对象语言的教程)都用一个画图的例子来展示多态的用途,我就不再重复这个例子了,如果你不知道这个例子,随便找本书应该都有介绍。我试图从一个抽象的角度描述一下,回头再结合那个画图的例子,也许你就更容易理解。
     
在面向对象的编程中,首先会针对数据进行抽象(确定基类)和继承(确定派生类),构成类层次。这个类层次的使用者在使用它们的时候,如果仍然在需要基类的时候写针对基类的代码,在需要派生类的时候写针对派生类的代码,就等于类层次完全暴露在使用者面前。如果这个类层次有任何的改变(增加了新类),都需要使用者“知道”(针对新类写代码)。这样就增加了类层次与其使用者之间的耦合,有人把这种情况列为程序中的“bad smell”之一。
     
多态可以使程序员脱离这种窘境。再回头看看上面的例子,bar()作为A-B这个类层次的使用者,它并不知道这个类层次中有多少个类,每个类都叫什么,但是一样可以很好的工作,当有一个C类从A类派生出来后,bar()也不需要“知道”(修改)。这完全归功于多态--编译器针对虚函数产生了可以在运行时刻确定被调用函数的代码。

5.2
如何“动态联编”
      
编译器是如何针对虚函数产生可以再运行时刻确定被调用函数的代码呢?也就是说,虚函数实际上是如何被编译器处理的呢?Lippman在深度探索C++对象模型[1]中的不同章节讲到了几种方式,这里把“标准的”方式简单介绍一下。

所说的“标准”方式,也就是所谓的“VTABLE”机制。编译器发现一个类中有被声明为virtual的函数,就会为其搞一个虚函数表,也就是VTABLE。VTABLE实际上是一个函数指针的数组,每个虚函数占用这个数组的一个slot。一个类只有一个VTABLE,不管它有多少个实例。派生类有自己的VTABLE,但是派生类的VTABLE与基类的VTABLE有相同的函数排列顺序,同名的虚函数被放在两个数组的相同位置上。在创建类实例的时候,编译器还会在每个实例的内存布局中增加一个vptr字段,该字段指向本类的VTABLE。通过这些手段,编译器在看到一个虚函数调用的时候,就会将这个调用改写。
void bar(A * a){    a->foo();   }
会被改写为:
void bar(A * a){    (a->vptr[1])();  }
因为派生类和基类的foo()函数具有相同的VTABLE索引,而他们的vptr又指向不同的VTABLE,因此通过这样的方法可以在运行时刻决定调用哪个foo()函数。虽然实际情况远非这么简单,但是基本原理大致如此。

5.3 overload
和override
      虚函数总是在派生类中被改写,这种改写被称为“override”。我经常混淆“overload”和“override”这两个单词。澄清一下:

    override
是指派生类重写基类的虚函数,就象我们前面B类中重写了A类中的foo()函数。重写的函数必须有一致的参数表和返回值(C++标准允许返回值不同的情况,这个我会在“语法”部分简单介绍,但是很少编译器支持这个feature)。这个单词好象一直没有什么合适的中文词汇来对应,有人译为“覆盖”,还贴切一些。
    overload
约定成俗的被翻译为“重载”。是指编写一个与已有函数同名但是参数表不同的函数。例如一个函数即可以接受整型数作为参数,也可以接受浮点数作为参数。


6
、 虚函数的语法
6.1  virtual
关键字
class A
{
public:
    virtual void foo();
};
class B: public A
{
public:
    void foo();    //
没有virtual关键字
!
};
class C: public B  //
从B继承,不是从A继承!

{
public:
    void foo();    //
也没有virtual关键字!
};
     
这种情况下,B::foo()是虚函数,C::foo()也同样是虚函数。因此,可以说,基类声明的虚函数,在派生类中也是虚函数,即使不再使用virtual关键字。

6.2  private
的虚函数
class A
{
public:
    void foo() { bar();}
private:
    virtual void bar() { ...}
};

class B: public A
{
private:
    virtual void bar() { ...}
};
      
在这个例子中,虽然bar()在A类中是private的,但是仍然可以出现在派生类中,并仍然可以与public或者protected的虚函数一样产生多态的效果。并不会因为它是private的,就发生A::foo()不能访问B::bar()的情况,也不会发生B::bar()对A::bar()的override不起作用的情况。

     
这种写法的语意是:A告诉B,你最好override我的bar()函数,但是你不要管它如何使用,也不要自己调用这个函数。

6.3
构造函数和析构函数中的虚函数调用
    一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们就变成普通函数了,不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。

当构造函数内部有虚函数时,会出现什么情况呢?结果是,只有在该类中的虚函数被调用,也就是说,在构造函数中,虚函数机制不起作用了,调用虚函数如同调用一般的成员函数一样。

当析构函数内部有虚函数时,又如何工作呢?与构造函数相同,只有“局部”的版本被调用。但是,行为相同,原因是不一样的。构造函数只能调用“局部”版本,是因为调用时还没有派生类版本的信息。析构函数则是因为派生类版本的信息已经不可靠了。我们知道,析构函数的调用顺序与构造函数相反,是从派生类的析构函数到基类的析构函数。当某个类的析构函数被调用时,其下一级的析构函数已经被调用了,相应的数据也已被丢失,如果再调用虚函数的最后一级的版本,就相当于对一些不可靠的数据进行操作,这是非常危险的。因此,在析构函数中,虚函数机制也是不起作用的。例如:
class A
{
public:
    A() { foo();}        //
在这里,无论如何都是A::foo()被调用!
    ~A() { foo();}       //
同上
    virtual void foo();
};

class B: public A
{
public:
    virtual void foo();
};

void bar()
{
    A * a = new B;
    delete a;
}
     
如果你希望delete a的时候,会导致B::foo()被调用,那么你就错了。同样,在new B的时候,A的构造函数被调用,但是在A的构造函数中,被调用的是A::foo()而不是B::foo()。

6.4
什么时候使用虚函数
    在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的。从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现。通过这样的方法,就可以将对象的行为抽象化。
“
如果你发现基类提供了虚函数,那么你最好override它”。
  

7、Things to Remember

       定义一个函数为虚函数,不代表函数为不被实现的函数。定义他为虚函数是为了允许用基类的指针来调用子类的这个函数。
      
定义一个函数为纯虚函数,才代表函数没有被实现。定义他是为了实现一个接口,起到一个规范的作用,规范继承这个。类的程序员必须实现这个函数。
   
有纯虚函数的类是不可能生成类对象的,如果没有纯虚函数则可以。

    
多态一般就是通过指向基类的指针来实现的。

4.
有一点你必须明白,就是用父类的指针在运行时刻来调用子类
:
例如,有个函数是这样的:

void animal::fun1(animal *maybedog_maybehorse)
{
     maybedog_maybehorse->born();

}
参数maybedog_maybehorse在编译时刻并不知道传进来的是dog类还是horse类,所以就把它设定为animal类,具体到运行时决定了才决定用那个函数。也就是说用父类指针通过虚函数来决定运行时刻到底是谁而指向谁的函数。


8
、用虚函数和不用虚函数
class animal
{
public:
     animal();
     ~animal();
     void fun1(animal *maybedog_maybehorse);
     virtual void born();
};
void animal::fun1(animal *maybedog_maybehorse)
{
     maybedog_maybehorse->born();
}

animal::animal() { }
animal::~animal() { }
void animal::born()
{
     cout<< "animal";
}
class horse:public animal
{
public:
     horse();
     ~horse();
     virtual void born();
};
horse::horse() { }
horse::~horse() { }
void horse::born()

{
     cout<<"horse";
}
void main()
{
     animal a; 
     horse b;
     a.fun1(&b); //output: horse //
如果不用虚函数则输出animal

}
9
、例子

class CBase...{
public:

CBase()...{

  cout<<"CBase Constructor! ";

  func();

   }

~CBase()...{

 cout<<"CBase deconstructor! ";

func();

}

virtual void func(){ cout<<"CBase::func() called! "; }

};
class CDerive: public CBase{

public:

    CDerive(){

 cout<<"CDerive Constructor! ";

func();

}

~CDerive(){

   cout<<"CDerive deconstructor! ";

func();

}

void func()...{ cout<<"CDerive::func() called! ";}

void func1()...{ func();  }      //调用虚函数

};

class CSubDerive: public CDerive...{

public:

CSubDerive()...{

cout<<"CSubDerive Constructor! ";

func();

}

~CSubDerive()...{

cout<<"CSubDerive deconstructor! ";

func();

}

void func()...{ cout<<"CSubDerive::func() called! ";}

};

void main()...{

CSubDerive obj;    //will produce "CBase::func() called!"

obj.func1();       //will produce "CSubDerive::func() called!"

}     

C++(多态,虚函数,构造函数,static) C++重要知识点(虚函数,拷贝构造函数,static) 阅读详情

相关推荐

Amesim与Simulink联合仿真:S-Function接口配置与实战避坑指南

本文详细介绍了Amesim与Simulink联合仿真中S-Function接口的配置方法与实战避坑指南。从环境搭建、编译器配置到S-Function接口实战,逐步解析关键步骤与常见问题解决方案,帮助工程师高效实现多领域系统仿真,特别适合汽车、航空航天等复杂系统建模场景。

weixin_29173777的博客 345

构造函数可以是虚函数吗?不看看你就亏大了

首先,构造函数是不能为虚函数的 调用构造函数后, 才能生成一个对象。 假设构造函数是虚函数, 虚函数存在于虚函数表中, 而去找虚函数表又需要虚函数指针, 而虚函数表指针又存在于对象中, 这样就矛盾了: 都没有生成对象, 哪有什么虚函数表指针呢? 那么问题又来了,析构函数可以是虚函数吗? 答:可以 把基类析构函数定义为虚函数,在调用析构函数时,会根据指向的对象类型到它的虚函数表中找到对应的虚函数,此时找到的是派生类的析构函数,因此调用该析构函数;而调用派生类析构函数之后会再调用基类的析构函数,因此不会导致内

m0_46657980的博客 7967

如何编译RustDesk(Unbuntu 和Android版本)

备注:官方文档上,一边都是基于sciter,这个在后面已经不建议使用了,但是依然可以编译刚开始的时候看官方的文档,涉及的东西比较多,也搞的一头雾水,通过B站上一个视频,可以通过CI/CD来编译,以及act本地试试(最终放弃,大概需要下载大几十G的容器下来)。最终总算明确了方向,可以用自动化流水线来编译。直接看CI/CD的脚本文件文件在.github/workflows目录下,重点研究 bridge.yml 和flutter-build.yml 这两个文件。

lvronglee的专栏 2549

C++构造函数、虚函数

一:构造函数 基本构造函数: 执行过程:1)传参 2)给类数据成员开辟空间 3)执行冒号语法给数据成员初始化 4)执行构造函数括号里面的内容 例如: class Base{ public: # 冒号语法后面的内容相当于int a = 10;(初始化) Base(int var) : m_Var(var){ } private: int m_...

qq26983255的博客 1971

echarts的坐标轴处理算法

参考原文:https://www.cnblogs.com/vicky-li/p/11653415.html。2、可用于双轴的情况,指定splitNumber,保证左右两边的线没有交叉显示的情况。1、设置echarts显示的最大最小值,让数据显示比较有起伏。处理echarts的一些问题。

HYeeee的博客 802

EXCEL VBA从入门到精通 第一章:VBA入门

在VBA中,需要使用关键字Dim来定义一个变量,后面跟上变量名和变量的数据类型。例如,下面的代码定义了一个整型变量x和一个字符串变量name在VBA中,使用关键字Const来定义常量,后面跟上常量名和常量的值。例如,下面的代码定义了一个整型常量MAX_NUM和一个字符串常量MESSAGE需要注意的是,常量一旦被定义,其值就不能被改变。

1万+

6.15C++:虚函数、构造函数不可以为虚函数、虚析构函数、虚函数实现多态、虚函数中默认参数、基类虚函数不能是私有函数、虚函数对象调用可内联,指针/引用调用不能内联

1 虚函数 虚函数可以实现运行时的多态,在运行时觉得调用哪个函数体; 虚函数必须是非静态的成员函数,虚函数是属于对象的,不是属于整个类的,需要在运行时通过指针定位到指向的对象,然后决定调用哪个函数体; 虚函数经过派生之后,就可以实现运行过程中的多态; 构造函数不能是虚函数,析构函数可以; 虚函数virtual只能出现在类定义的函数原型声明中,而不能在成员函数实现的时候; 虚函数不能是内联函数,因为对虚函数的调用需要动态绑定,而对内联函数的处理是静态的 #include <iostream>

weixin_44478659的博客 632

5.30华为OD机试真题 新系统 - 链表数字游戏 (Java/Py/C/C++/Js/Go)

5.30华为OD机试真题 新系统 - 链表数字游戏 (Java/Py/C/C++/Js/Go)

算法大师! 1126

C++ 构造函数和析构函数可以是虚函数嘛?

简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 构造函数不能是虚函数 1. 从vptr角度解释 虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还...

Magnum的博客 1万+

PMP--工件

合同是指对双方都有约束力的协议,强制卖方提供规定的产品、服务或结果,以及强制买方支付相应的费用。它还可能包括处于中间状态的特性,例如已设计但尚未构建的特性、质量保证中的特性或测试中的特性。RACI 矩阵是一种常见的方法,用于显示执行、担责、咨询或知情,且与项目活动、决策和可交付物有关的干系人。计划是提议的实现某种目标的方式。在项目开始前或开始时创建的文件,涉及与项目有关的战略、商业或高层级的信息。或 © 它们是用特定方法创建的结果,例如,虽然成本估算结果是一个重要工件,它们是用不同估算方法得出的结果。

stqer的博客 1666

团体程序设计天梯赛竞赛题--登顶题【L3-042 污染大亨】

登顶级 3 道题,每道题 30 分,满分为 90 分。

Pretty Boy Fox的博客 1362

构造函数、析构函数、多态、虚函数、纯虚函数、虚析构函数、拷贝构造函数、protected、private、public

用来实现多态,允许基类的函数被实例化。通过在基类中声明虚函数,并在派生类中进行重写,实现了在运行时根据对象的实际类型选择合适的函数实现。

Ceri的博客 1827

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(三)

基于若依的ruoyi-nbcio-plus支持VForm3表单字段数据保存到数据库的一种方法——全网首创(三)

宁波阿成的博客 526

C++ 构造函数和析构函数是否可以为虚函数?

简单总结就是:构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 理由如下: 构造函数不能是虚函数 1.从vptr角度解释 虚函数的调用是通过虚函数表来查找的,而虚函数表由类的实例化对象的vptr指针(vptr可以参考C++的虚函数表指针vptr)指向,该指针存放在对象的内部空间中,需要调用构造函数完成初始化。如果构造函数是虚函数,那么调用构造函数就需要去找vptr,但此时vptr还没有初始化! 2.从多态角度解释 虚函数主要是实现多态,在运行时才可以明确调用对象,根据传入的对象类型来调用函数,例如通过

TABE_的博客 7841

pscad IEEE标准系统搭建说明

pscad IEEE标准系统搭建说明,包含典型的IEEE 9节点、14节点、30节点、39节点和118节点系统。内含标准测试系统的原始数据和潮流结果。

ssm框架搭建

这个是一个在idea上成功跑起来的ssm框架项目,保存在这里方便以后使用直接下载

C++ 构造函数、析构函数与虚函数

此外class B的公共成员中还有一个属于自己的函数 void func2(),注意,这里面的函数func2虽然与class A中的函数func2同名,但是他们是互补相关的两个函数,也不存在谁覆盖谁,因为他们并没有将该同名函数申明为virture function(虚函数),所以class B的对象在调用void func2()的时候,它只能调用到class B自身公共成员函数中的void func2()函数,而无法调用到class A 中的void func2()函数。其次,调用构造函数。

Vesan的博客 1716

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

构造函数和析构函数可以是虚函数吗?为什么?

三、构造函数和析构函数可以是虚函数吗?为什么? 1、构造函数 从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数。 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用。构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀。所以构造函数没有

Yy的博客 5459

构造函数和析构函数可以是虚函数吗?

构造函数可以是虚函数吗,为什么 答:不可以 因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。 C++之父 Bjarne Stroustrup 在《The C++ Programming Language》里说: To construct an object, a constructor needs the exact type of the object it is to crea...

qq_41830537的博客 4633

为什么析构函数可以为虚函数但是构造函数不能为虚函数

构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。 不建议在构造函数和析构函数里面调用虚函数。 构造函数不能声明为虚函数的原因是: 1 构造一个对象的时候,必须知道对象的实际类型,而虚函数行为是在运行期间确定实际类型的。而在构造一个对象时,由于对象还未构造成功。编译器无法知道对象 的实际类型,是该类本身,还是该类的一个派生类,或是更深层次的派生类。无法确定。。。 2 虚函数的执行依赖于虚函数表。而虚函数表在构造函数中进行初始化工作,即初始化vptr,让他指向正确的虚函数表。而在

flf1234567898的博客 1166

构造函数、析构函数、虚函数

文章目录为什么构造函数不能为虚函数?为什么析构函数要定义为虚函数?虚函数的工作原理?有关虚函数的几个知识点 为什么构造函数不能为虚函数? 参考回答: 在类中,构造函数用于初始化对象及相关操作。 构造函数是不能声明为虚函数的,因为虚函数对应一个virtual table(虚函数表),这个表的地址是存储在对象的内存空间的。 而在执行构造函数前,对象尚未完成创建,内存都没有被分配,所以无法去查询虚函数表...

yiliacheng 996

C++:构造函数和析构函数可以是虚函数吗

先说结论:C++中,构造函数不可以是虚函数,而析构函数可以且常常是虚函数。 虚函数的定义:类成员函数前面添加virtual关键字,则函数被称为虚函数。 1、构造函数不可以是虚函数 当类中声明虚函数时,编译器会在类中生成一个虚函数表,虚函数表是一个存储成员函数指针的数据结构。 虚函数表是由编译器自动生成与维护的,virtual成员函数会被编译器放入虚函数表中,当存在虚函数时,每个对象都有一个指向虚函数的指针(vptr指针)。在实现多态的过程中,父类和派生类都有vptr指针。 vptr的初始化:当对象

Taopper的博客 3426

为什么构造函数不能是虚函数?析构函数可以是虚函数吗?

构造函数不能声明为虚函数,析构函数可以声明为虚函数,而且有时是必须声明为虚函数。 抽象类中构造和析构均不能使用纯虚函数。 为什么构造函数不能声明为虚函数呢? 1、构造一个对象的时候,必须知道对象的实际类型,而虚函数是在运行期间确定实际类型的。如果构造函数为虚函数,则在构造一个对象时,由于对象还未构造成功,编译器还无法知道对象的实际类型,是该类本身还是派生类。无法确定。 2、虚函数的执行依赖于虚函数表,而虚函数表是在构造函数中初始化的,即初始化vptr,让它指向虚函数表。如果构造函数为虚函数,则在构造

LQB的梦烦了的博客 5938

在C++中为什么构造函数不能是虚函数,而析构函数可以

、为什么构造函数不可以是虚函数 ①从存储空间角度     虚函数对应一个vtable(虚函数表),这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 ②从使用角度         虚函数主要用于在信息不全的情况下,能使重载的函数...

cainiao000001的博客 7422

c++ 虚函数 构造函数 析构函数

一、虚函数和构造函数         当创建一个含有虚函数的对像是,必须初始化它的VPTR以指向相应的VTABLE,这必须在对虚函数进行任何调用之前完成,而设置VPTR这项工作是由构造函数来完成。编译器在构造函数的开头部分秘密地插入能初始化VPTR的代码,如果我们没有为一个类显式创建构造函数,则编译器会为我们生成构造函数。如果该类含有虚函数,则生成的构造函数将会包含相应的VPTR初始化代码。

再见理想 950

为什么C++的构造函数不可以是虚函数,而析构函数可以是虚函数

1、为什么构造函数不可以是虚函数 ①从存储空间角度 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的。问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数。 ②从使用角度 虚函数的作用在于通过父类的指针或者引用来调用它的时候能...

qq826364410的专栏 881

C++构造函数、析构函数、虚函数

今天看书时发现对c++虚函数、构造函数、析构函数的一些概念竟然极其不清晰。 查了一些书,总结一下。 构造函数 1.创建对象时会依次调用基类和子类的构造函数,各个构造函数负责对自己类中定义的成员的初始化工作。 2.如果用户不声明任何构造函数,编译器将提供一个缺省构造函数(default constructor),只要用户定义了自己的构造函数,不论包不包括缺省构造函数,编译器都不再提供缺省构造

super_chris的专栏 2668

构造函数及析构函数与虚函数的关系

我们都知道构造函数不能为虚函数,而基类的析构函数一般都要定义为虚函数。今天重新复习了一下,特在此记载,以便查找。构造函数不能为虚函数主要有以下两点1、必要性分析: 当定义派生类对象时,它会主动依次调用构造函数,顺序为基类的构造函数->一级派生类构造函数->二级派生类构造函数….直到当前派生类的构造函数调用完毕为止,到此派生类对象生成。 而虚函数存在的意义为动态绑定,从上一段话可知,它会从基类开始

linpengbin的专栏 2537
上一篇: 虚函数表
下一篇: c++获取系统时间
proing
博客等级 码龄19年 2092粉丝 94原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值