虚函数

The C++ Programming Language第二章

て烟熏妆下的殇ゞ 提交于 2020-03-12 13:01:57
1、虚函数 P33      即使调用者并不知道 对象的大小以及它的数据布局 , 位于vtbl里的 函数 也使对象能正确地使用 。 调用者需要知道的 所有 东西 就是 Stack的那个 vtbl 的位置 ,以及对各个 虚函数 应该使用的 下标 。这种虚函数 调用机制的效率可以做得基本上与“正常函数调用”机制相同 。其 空间 开销是带有虚函数的类的每个对象里包含一个指针,而每个这样的类需要有一个vtbl。 2、模板是一种 编译时 的机制,因此,与“手工编写的代码”相比,它们的使用并不引起任何额外的 运行时开销 。P37 3、学习一种语言的工作就应该集中于把我对该语言而言固有的和自然的风格--而不是去理解该语言的所有语言特征的细枝末节。P39   在实践性的程序设计中,理解语言中最晦涩难懂的语言特征,或者使用最大量的不同特征并不能获得什么利益。把一种特征鼓励起来看并没有什么意思,只是在由技术和其他特征所形成的环境里,这一特征才获得了意义和趣味。    PS:3、这段话还是理解不了。 4、 你并不需要在知道了C++的所有细节之后才能洗出好的C++程序。 P39 5、 请特别关注程序设计技术,而不是各种语言特征。 P39 ~~end~~ !!欢迎添加!! 来源: https://www.cnblogs.com/ziyoudefeng/archive/2012/04/17/2454336

The Programming Language Idioms

好久不见. 提交于 2020-03-12 13:01:29
The Programming Language Idioms Click below to go directly to a specific section: 重载与重写 | 静态构造函数 | 只读代理 | 同步代理 | 资源管理 | 构造函数中的虚函数 强制针对接口编程 | 抗变与协变 | friend interface | ctor vs. setter | 杂项 重载与重写 问题 日常讨论中,术语的不统一带来些许混乱 惯用的表达 overload 重载 函数名称相同,参数不同(严格的定义还有其它一些限制) 静态决议 override 重写(覆写,覆盖,改写) 子类重新定义父类定义过的虚函数(个别语言允许返回值,访问级别可以不同) 动态决议 示例 class Base { } class Derived:Base { } class Client { void Test(Base obj){ Console.WriteLine("base"); } void Test(Derived obj){ Console.WriteLine("derived"); } static void Main( string [] args) { Base obj = new Derived(); new Client().Test(obj); //输出“base” } } 静态构造函数

C++类的大小计算汇总

≯℡__Kan透↙ 提交于 2020-03-11 03:59:33
  C++中类涉及到虚函数成员、静态成员、虚继承、多继承、空类等。   类,作为一种类型定义,是没有大小可言的。   类的大小,指的是类的对象所占的大小。因此,用sizeof对一个类型名操作,得到的是具有该类型实体的大小。 类大小的计算,遵循结构体的对齐原则; 类的大小,与普通数据成员有关,与成员函数和静态成员无关。即普通成员函数、静态成员函数、静态数据成员、静态常量数据成员,均对类的大小无影响; 虚函数对类的大小有影响,是因为虚函数表指针带来的影响; 虚继承对类的大小有影响,是因为虚基表指针带来的影响; 静态数据成员之所以不计算在类的对象大小内,是因为类的静态数据成员被该类所有的对象所共享,并不属于具体哪个对象,静态数据成员定义在内存的全局区; 空类的大小( 类的大小为1 ),以及含有虚函数,虚继承,多继承是特殊情况; 计算涉及到内置类型的大小,以下所述结果是在64位gcc编译器下得到(int大小为4,指针大小为8); 一、简单情况的计算 #include<iostream> using namespace std; class base { public: base()=default; ~base()=default; private: static int a; int b; char c; }; int main() { base obj; cout<<sizeof

C++三大特性

青春壹個敷衍的年華 提交于 2020-03-10 23:58:03
封装继承和多态 封装:隐藏实现细节,使得代码模块化,封装就是把过程和数据包装,将客观事物封装成抽象的类,并且类可以把自己的数据和方法只让可信的类或者对象操纵,对其他信息隐藏。 类继承是指C++提供来扩展和修改类的方法,类继承就是从已有的类中派生出新的类,派生类继承了基类的特性,同时可以添加自己的特性,继承又分为 单一继承 多重继承 菱形继承 多态是在具有继承关系的类对象中去调用某一虚函数时(使用基类的指针/引用去调用同一函数),产生了不同的行为,构成多态的条件有两个( 说白了就是通过指针/引用在不同时候调用同一函数可能调用的是不同的版本,多态是指接口的多种不同实现方式 ) 调用函数的对象必须是指针或者引用 被调用的函数必须是虚函数,且完成了虚函数的重写(不覆盖会调用派生类的函数吗?) 动态(类型)绑定/静态(类型)绑定 静态类型:对象在声明时的类型,其在编译时决定 动态类型:变量所指向内存中该对象的类型(通常指指针/引用所绑定对象的类型),在运行期决定 静态类型决定了某个函数能不能被调用,而动态类型则在动态绑定发生时决定调用该函数的哪个版本 如果不使用指针和引用,则静态类型和动态类型一定相同 静态绑定:也叫静态联编,绑定的是对象的静态类型,某特性(比如函数)依赖于对象的静态类型,发生在编译器 动态绑定:也叫动态联编,绑定的是对象的动态类型,某特性(比如函数)依赖于对象的动态类型

C++学习(十五)—多态(一)

蓝咒 提交于 2020-03-10 00:22:19
多态 多态分类 静态多态:运算符重载 函数重载 动态多态:父子之间继承 + 虚函数 动态多态满足的条件 父类中有虚函数 子类重写父类的虚函数 父类的指针或者引用指向子类的对象 注意:子类重新实现父类中的虚函数,必须返回值、函数名、参数一致才称为重写 子类在做重写的时候,可以不加关键字virtual 多态原理 当父类中存在虚函数后,内部发生结构变化 多了指针 vfptr 虚函数表指针—指向 虚函数表 vftable 虚函数表内部记录着虚函数的地址 当子类发生重写后,会修改子类中的虚函数表中的函数地址,但是并不会影响父类中的虚函数表 # include <iostream> using namespace std ; // 空类的大小 1 class Animal { public : virtual void speak ( ) // 加上virtual关键字后 speak函数变为虚函数 { cout << "动物在说话" << endl ; } } ; class Cat : public Animal { public : void speak ( ) { cout << "小猫在说话" << endl ; } } ; // 静态联编 -- 地址早绑定 // 利用动态联编 -- 地址晚绑定 virtual // 多态满足的条件 // 1、父类中有虚函数 // 2

C++中的类所占内存空间总结

帅比萌擦擦* 提交于 2020-03-09 17:10:02
说明:此博文转载之 http://blog.sina.com.cn/s/blog_69c189bf0100mkeu.html 类所占内存的大小是由成员变量( 静态变量除外 )决定的, 成员函数(这是笼统的说,后面会细说) 是不计算在内的。 摘抄部分: 成员函数还是以一般的函数一样的存在。 a.fun()是通过fun(a.this)来调用的 。所谓成员函数只是在名义上是类里的。 其实成员函数的大小不在类的对象里面,同一个类的多个对象共享函数代码。 而我们访问类的成员函数是通过类里面的一个指针实现,而这个指针指向的是一个table,table里面记录的各个成员函数的地址(当然不同的编译可能略有不同的实现)。所以我们访问成员函数是间接获得地址的。所以这样也就增加了一定的时间开销,这也就是为什么我们提倡把一些简短的,调用频率高的函数声明为inline形式(内联函数)。 (一) class CBase { }; sizeof(CBase)=1; 为什么空的什么都没有是1呢? c++要求每个实例在内存中都有独一无二的地址。// 注意这句话!!!!!!!!!! 空类也会被实例化,所以编译器会给空类隐含的添加一个字节,这样空类实例化之后就有了独一无二的地址了。所以空类的sizeof为1。 (二) class CBase { int a; char p; }; sizeof(CBase)=8; 记得

c++中各类型数据所占字节数(二)

这一生的挚爱 提交于 2020-03-09 10:45:59
转自: https://blog.csdn.net/allen_tony/article/details/76973906 https://blog.csdn.net/zzwdkxx/article/details/53635173 关于多个父类,虚继承,类本身自己的虚函数,情况比较复杂,后续时间再研究。 类所占内存的大小是由成员变量(静态变量除外)决定的,成员函数是不计算在内的。摘抄部分: 成员函数还是以一般的函数一样的存在。a.fun()是通过fun(a.this)来调用的。所谓成员函数只是在名义上是类里的。其实成员函数的大小不在类的对象里面,同一个类的多个对象共享函数代码。而我们访问成员函数是通过类里面的一个指针实现,而这个指针指向的是一个table,table里面记录的各个成员函数的地址(当然不同的编译可能略有不同的实现)。所以我们访问成员函数是间接获得地址的。所以这样也就增加了一定的时间开销,这也就是为什么我们提倡把一些简短的,调用频率高的函数声明为inline形式(内联函数)。 如果类定义了虚函数,该类及其派生类就要生成一张虚拟函数表,即vtable。而在类的对象地址空间中存储一个该虚表的入口,占4个字节,这个入口地址是在构造对象时由编译器写入的。 所以,由于对象的内存空间包含了虚表入口,编译器能够由这个入口找到恰当的虚函数,这个函数的地址不再由数据类型决定了。

C++类所占内存大小计算

旧城冷巷雨未停 提交于 2020-03-09 10:41:23
C++类所占内存大小计算 转载时请注明出处和作者联系方式 文章出处: http://blog.csdn.net/chenchong08 作者联系方式: vision_chen@yeah.net 说明:笔者的操作系统是32位的。 class A {}; sizeof( A ) = ? sizeof( A ) = 1 明明是空类,为什么编译器说它是1呢? 空类同样可以实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以sizeof( A )的大小为1. class B { public: B() {} ~B() {} void MemberFuncTest( int para ) { } static void StaticMemFuncTest( int para ){ } }; sizeof( B ) = ? sizeof( B ) = 1 类的非虚成员函数是不计算在内的,不管它是否静态。 class C { C(){} virtual ~C() {} }; sizeof( B ) = ? sizeof( B ) = 4 类D有一个虚函数,存在虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放的就是虚函数的地址了,因此,虚表是属于类的。这样的类对象的前四个字节是一

C++类所占内存大小计算

落花浮王杯 提交于 2020-03-09 10:29:22
C++类所占内存大小计算 文章出处:http://blog.csdn.net/chenchong08 作者联系方式:vision_chen@yeah.net 说明:笔者的操作系统是32位的。 class A {}; sizeof( A ) = ? sizeof( A ) = 1 明明是空类,为什么编译器说它是1呢? 空类同样可以实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以sizeof( A )的大小为1. class B { public: B() {} ~B() {} void MemberFuncTest( int para ) { } static void StaticMemFuncTest( int para ){ } }; sizeof( B ) = ? sizeof( B ) = 1 类的非虚成员函数是不计算在内的,不管它是否静态。 class C { C(){} virtual ~C() {} }; sizeof( B ) = ? sizeof( B ) = 4 类D有一个虚函数,存在虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放的就是虚函数的地址了,因此,虚表是属于类的。这样的类对象的前四个字节是一个指向虚表的指针,类内部必须得保存这个虚表的起始指针

C++类所占内存大小计算

喜你入骨 提交于 2020-03-09 10:16:56
C++类所占内存大小计算 说明:笔者的操作系统是32位的。 class A {}; sizeof( A ) = ? sizeof( A ) = 1 明明是空类,为什么编译器说它是1呢? 空类同样可以实例化,每个实例在内存中都有一个独一无二的地址,为了达到这个目的,编译器往往会给一个空类隐含的加一个字节,这样空类在实例化后在内存得到了独一无二的地址.所以sizeof( A )的大小为1. class B { public: B() {} ~B() {} void MemberFuncTest( int para ) { } static void StaticMemFuncTest( int para ){ } }; sizeof( B ) = ? sizeof( B ) = 1 类的非虚成员函数是不计算在内的,不管它是否静态。 class C { C(){} virtual ~C() {} }; sizeof( B ) = ? sizeof( B ) = 4 类D有一个虚函数,存在虚函数的类都有一个一维的虚函数表叫虚表,虚表里存放的就是虚函数的地址了,因此,虚表是属于类的。这样的类对象的前四个字节是一个指向虚表的指针,类内部必须得保存这个虚表的起始指针。在32位的系统分配给虚表指针的大小为4个字节,所以最后得到类C的大小为4. class D { D(){} virtual ~D(