先看一个例子: #include <iostream> using namespace std; class A{ public: A() { show(); } virtual void show(){ cout<<"in A"<<endl; } virtual ~A(){ show(); } }; class B:public A{ public: B() { show(); } void show(){ cout<<"in…
构造函数和析构函数中的虚函数 在执行基类构造函数时,对象的派生类部分是未初始化的.实际上,此时对象还不是一个派生类对象. 为 了适应这种不完整,编译器将对象的类型视为在构造或析构期间发生了变化.在基类构造函数或析构函数中,将派生类对象当作基类类型对象对待.   如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本.   class Base { public: Base() { Fuction(); } virtual void Fuction() { cout…
从存储空间角度,虚函数对应一个指向vtable虚函数表的指针,这大家都知道,可是这个指向vtable的指针其实是存储在对象的内存空间的.问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用.构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀.所以构造函数没有必要是虚函数.虚函数的作用在于通过父类的指针或者引用来…
一.构造函数为什么不能为虚函数 1. 从存储空间角度,虚函数相应一个指向vtable虚函数表的指针,这大家都知道,但是这个指向vtable的指针事实上是存储在对象的内存空间的.问题出来了,假设构造函数是虚的,就须要通过 vtable来调用,但是对象还没有实例化,也就是内存空间还没有,怎么找vtable呢?所以构造函数不能是虚函数. 2. 从使用角度,虚函数主要用于在信息不全的情况下,能使重载的函数得到相应的调用.构造函数本身就是要初始化实例,那使用虚函数也没有实际意义呀.所以构造函数没有必要是虚…
C++构造函数.析构函数.虚函数之间的关系 1. 如果我们定义了一个构造函数,编译器就不会再为我们生成默认构造函数了.2. 编译器生成的析构函数是非虚的,除非是一个子类,其父类有个虚析构,此时的函数虚特性来自父类.3. 有虚函数的类,几乎可以确定要有个虚析构函数.4. 如果一个类不可能是基类就不要申明析构函数为虚函数,虚函数是要耗费空间的.5. 析构函数的异常退出会导致析构不完全,从而有内存泄露.最好是提供一个管理类,在管理类中提供一个方法来析构,调用者再根据这个方法的结果决定下一步的操作.6.…
1.继承构造函数调用顺序以及销毁的过程 先调用父类的构造函数,在调用子类的构造函数,析构函数调用相反.…
在构造函数中调用虚函数,并不会产生多态的效果,就跟普通函数一样. c++ primer 第四版中497页15.4.5构造函数和析构中的虚函数讲到,如果在构造函数或析构函数中调用虚函数,则运行的是为构造函数或析构函数自身类型定义的版本.另外,必须通过基类类型的引用或指针进行函数调用才会发生多态. 相关帖子:http://bbs.csdn.net/topics/390537893 //示例1 #include <iostream> using namespace std; class A { pr…
编译环境:windows 10 + VS2105 1.构造函数不能为虚函数 虚函数的作用是为了实现C++多态机制.基类定义虚函数,子类可以重写该虚函数.当子类重写父类虚函数后,父类指针指向子类地址时,父类指针根据赋给它不同子类的指针,动态调用该子类的该函数,而不是父类的对应函数(当子类没重写该函数时,则调用父类对应的函数).且这样的函数调用发生在运行阶段,而不是发生的编译阶段,称为动态联编(注意:函数重载也可以认为是多态,只不过是静态的,在编译阶段确定了函数调用方式.非虚函数静态联编效率比虚函数…
做项目的过程中,碰到一个问题. 问题可以抽象为下面的问题: 普通人吃饭拿筷子,小孩吃饭拿勺子. class People { public: void eat() { get_util_to_eat(); } virtual void get_util_to_eat() { std::cout << "People get chopsticks" << std::endl; } }; class Children : public People { public…
#include <iostream> class cx { public: virtual void func() { std::cout << "func" << std::endl; } cx() { func(); //构造函数中调用虚函数,语法上OK,效果上不对,因为当对象由子类进入基类构造时是基类类型的 //不管如何调用,总只能调用到基类的虚函数,无法调用到子类的虚函数,见下面测试 } }; class cb : public cx {…
1. 存储空间角度:虚函数对应一个vtable,vtable存储于对象的内存空间 若构造函数是虚的,则需要通过 vtable来调用,若对象还未实例化,即内存空间还没有,无法找到vtable 2. 使用角度:虚函数主要用于在信息不全的情况下,能使重载的函数得到对应的调用. 构造函数本身就是要初始化实例,那使用虚函数就没有实际意义 3. 从实际含义上看,在调用构造函数时还不能确定对象的真实类型(因为子类会调父类的构造函数):而且构造函数的作用是提供初始化,在对象生命期只执行一次,不是对象的动态行为,…
单个对象创建时,构造函数的调用顺序 1.首先判断该对象的类是否拥有父类,若有则先调用父类的构造函数 2.判断该对象的成员是否是其它类的成员,若是则调用成员变量的构造函数(调用顺序和声明顺序相同) 3.最后调用对象本身类的构造函数 单个对象被注销后,调用的析构函数与对应构造函数的调用顺序相反 参考下面示例,创建两个类Member,Test,然后Tesrt成员包含了Member类的成员: #include <stdio.h> class Member { const char* ms; publi…
今天看书忽然对这个地方有点模糊,尤其是析构函数在调用默认的析构函数和用户自己覆写的析构函数的时候有点意识模糊呢.写段代码总结下 #include <iostream> using namespace std; class Box { private: double length; public: Box(double lv=1.0):length(lv)//构造函数都没有返回值 { cout << "constructor called" << en…
/*当建立一个对象时,首先调用基类的构造函数,然后调用下一个派生类的构造函数,依次类推,直至到达派生类次数最多的派生次数最多的类的构造函数为止.简而言之,对象是由“底层向上”开始构造的.因为,构造函数一开始构造时,总是要调用它的基类的构造函数,然后才开始执行其构造函数体,调用直接基类构造函数时,如果无专门说明,就调用直接基类的默认构造函数.在对象析构时,其顺序正好相反.下面的这个程序说明这个问题*///-----------------------------------------------…
示例函数 注:输出并不一定从main函数开始,如全局对象的初始化在main函数前执行,如构造函数中存在输出,则从构造函数的输出开始 此处6被类型转换构造函数的存在转换为临时对象赋值,而在这个过程结束后临时对象消亡则调用析构函数 注2:局部变量生存期是碰到函数开始到最内存函数右边花括号 注3:静态局部变量则会留存到整个程序结束 注4:构造函数并非分配变量的存储空间,而是负责初始化,而析构函数也不负责收回变量的存储空间 注5:new的对象如果不用delete删除则不会消亡,不会触发析构函数,即使整个…
一.基类     从一个类派生出另一个类时,原始类称为基类,继承类称为派生类. 派生类对自身基类的private成员没有访问权限,对基类对象的protected成员没有访问权限,对派生类对象的(基类之外)的private和protected成员具有访问权限. 由于C++基础不好,平时也不用它,导致今天才纠正一个非常关键的错误,类的访问权限,是对类而言的,而不是对类的对象而言的.一直都理解错了.这句话都没脸写出来,还是写下来了. 下面是一段简答的测试代码.对于调用成员函数的对象test,基类形参,…
1.构造函数不能为虚函数 当我们将构造函数定义为虚函数时,会直接报错: 首先回忆下以前学的virtual虚函数概念: 如果类定义了虚函数,创建对象时,则会分配内存空间,并且为该父类以及其所有子类的内存空间上额外分配一个虚函数表. 虚函数表的作用在于,存储每个类的相同的虚函数名,然后每一次虚函数调用,都会去虚函数表查找地址 分析: 假如构造函数是虚函数的话,由于对象开始还未分配内存空间,所以根本就无法找到虚函数表,从而构造函数也无法被调用.所以构造函数是不能成为虚函数. 2. 析构函数可以为虚函数…
1.不要在构造函数中调用虚函数的原因 在概念上,构造函数的工作是为对象进行初始化.在构造函数完成之前,被构造的对象被认为“未完全生成”.当创建某个派生类的对象时,如果在它的基类的构造函数中调用虚函数,那么此时派生类的构造函数并未执行,所调用的函数(派生类的虚函数)可能操作还没有被初始化的成员,将导致灾难的发生. 2.不要在析构函数中调用虚函数的原因 同样的,在析构函数中调用虚函数,函数的入口地址也是在编译时静态决定的.也就是说,实现的是实调用而非虚调用. 考察如下例子. #include <io…
1 虚函数对应一个vtable,这大家都知道,可是这个vtable其实是存储在对象的内存空间的.问题出来了,如果构造函数是虚的,就需要通过 vtable来调用,可是对象还没有实例化,也就是内存空间还没有,无法找到vtable,所以构造函数不能是虚函数. 2. 构造函数不需要是虚函数,也不允许是虚函数,因为创建一个对象时我们总是要明确指定对象的类型,尽管我们可能通过实验室的基类的指针或引用去访问它.但析构却不一定,我们往往通过基类的指针来销毁对象.这时候如果析构函数不是虚函数,就不能正确识别对象类…
学习C++ 不可避免地会遇到虚函数的问题,下面几个问题在学习初期或多或少会存在一些疑惑,所以便将其总结了下来. 1.为什么静态成员函数.构造函数不能定义为虚函数? 因为静态成员函数是一个大家共享的一个资源,它其实就是一个“受类域限定符限制”的普通函数,没有this指针,不需要对象就可以调用:而虚函数是实打实的成员函数,调用依赖于创建的实例(编译时要把实例的地址给该成员函数的this指针) 所以一个依赖对象,一个则不,两者是是相矛盾的. 对构造函数来说,因为在用运行构造函数来构造实例的时候,实例还…
http://www.cnblogs.com/CaiNiaoZJ/archive/2011/08/11/2134673.html 多态性 指相同对象收到不同消息或不同对象收到相同消息时产生不同的实现动作. C++支持两种多态性:编译时多态性,运行时多态性. a. 编译时多态性:通过重载函数和运算符重载实现. b. 运行时多态性:通过虚函数和继承实现.   虚函数 虚函数是在基类中被声明为virtual的函数.为了重载和多态的需要,在基类中是有定义的,即便定义是空,所以子类中可以重写也可以不写基类…
1.虚函数的代价 1)带有虚函数的每个类会产生一个虚函数表,用来存储虚成员函数的指针 2)带有虚函数的每个类都会有一个指向虚函数表的指针 3)不再是内敛函数,因为内敛函数可以在编译阶段进行替代,而虚函数表示等待,在运行阶段才能确定到达采用哪种函数,所以虚函数不是内敛函数 2.那些函数不能是虚函数? 1)构造函数:对象的虚函数表指针需要通过构造函数初始化 2)内联函数:内联函数可以在编译阶段进行函数体的替换,而虚函数需要在运行期间进行确定 3)静态函数:静态函数不属于对象而属于类,因为静态成员函数…
在你设计一个基类的时候,如果发现一个函数需要在派生类里有不同的表现,那么它就应该是虚的.从设计的角度讲,出现在基类中的虚函数是接口,出现在派生类中的虚函数是接口的具体实现.通过这样的方法,就可以将对象的行为抽象化. 1.虚函数(impure virtual),C++的虚函数主要作用是“运行时多态”,父类中提供虚函数的实现,为子类提供默认的函数实现. 子类可以重写父类的虚函数实现子类的特殊化. 2.纯虚函数(pure virtual),C++中包含纯虚函数的类,被称为是“抽象类”.抽象类不能使用n…
构造函数不可以是虚函数的,这个很显然,毕竟虚函数都对应一个虚函数表,虚函数表是存在对象内存空间的,如果构造函数是虚的,就需要一个虚函数表来调用,但是类还没实例化没有内存空间就没有虚函数表,这根本就是个死循环. 可是析构函数却要定义成虚函数,这是为什么呢,写一个非常简单的例子来理解一下: class AA { public: AA() {}; ~AA() { fun2(); }; virtual void fun1() { cout << "Base construct" &…
类中的成员函数分为静态成员函数和非静态成员函数,而非静态成员函数又分为普通函数和虚函数. Q: 为什么使用虚函数 A: 使用虚函数,我们可以获得良好的可扩展性.在一个设计比较好的面向对象程序中,大多数函数都是与基类的接口进行通信.因为使用基类接口时,调用基类接口的程序不需要改变就可以适应新类.如果用户想添加新功能,他就可以从基类继承并添加相应的新功能. Q: 简述C++虚函数作用及底层实现原理 A: 要点是要答出虚函数表和虚函数表指针的作用. 虚函数是用来实现动态绑定的. C++中虚函数使用虚函…
0.目录 1.动态内存分配 1.1 new和malloc的区别 1.2 delete和free的区别 2.虚函数 2.1 构造函数与析构函数是否可以成为虚函数? 2.2 构造函数与析构函数是否可以发生多态? 3.继承中的强制类型转换 4.小结 1.动态内存分配 1.1 new和malloc的区别 new关键字与malloc函数的区别: new关键字是C++的一部分 malloc是由C库提供的函数 new以具体类型为单位进行内存分配 malloc以字节为单位进行内存分配 new在申请内存空间时可进…
运算符重载与虚函数 单目运算符 接下来都以AClass作为一个类例子介绍 AClass{ int var } 区分后置++与前置++ AClass operator ++ () ++前置 一般设计为返回引用 这样的话可以将其作为左值(自然也可以作为右值,会调用该类的拷贝构造函数) ++class = ... AClass operator ++ (int) 后置++ 一般设计返回一个旧的类 获得的是历史版本,所含有的int形参是用作区分类型的,并无实际含义 由于一个__单变量__的构造函数可被视…
只有用virtual声明类的成员函数,使之成为虚函数,不能将类外的普通函数声明为虚函数.因为虚函数的作用是允许在派生类中对基类的虚函数重新定义.所以虚函数只能用于类的继承层次结构中. 一个成员函数被声明为虚函数后,在同一类族中的类就不能再定义一个非virtual的但与该虚函数具有相同的参数(包括个数和类型)和函数返回值类型的同名函数. 根据什么考虑是否把一个成员函数声明为虚函数? ①  看成员函数所在的类是否会作为基类 ② 看成员函数在类的继承后有无可能被更改功能,如果希望更改其功能的,一般应该…
1.纯虚函数 成员函数的形参后面写上=0,则成员函数为纯虚函数. 纯虚函数声明: virtual 函数类型 函数名 (参数表列) = 0: class Person { virtual void Display () = 0; // 纯虚函数 protected : string _name ; // 姓名 }; class Student : public Person {}; 注意: (1)纯虚函数没有函数体: (2)最后面的“=0”并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“…
1.虚函数(impure virtual) c++虚函数主要是提供“运行时多态”,父类提供虚函数的默认实现,子类可以虚函数进行重写. 2.纯虚函数(pure virtual)       c++纯虚函数也是“运行时多态”,父类不能提供函数的实现,子类提供函数的实现.包含纯虚函数的类,称为“”抽象类“”,无法用new 实现对象,只能实现了虚函数的子类才可以new. 3.普通函数(no-virtual)      普通函数是静态编译的,是父类给子类提供的强制实现. 4,多态概念    相同对象收到不…