虚函数

牛客 C++刷题day43

怎甘沉沦 提交于 2019-12-01 09:54:03
1.+重载符号前面的操作数必须是一个对象。 2.关联容器(如map, set, multimap,multiset),删除当前的iterator,只会使当前的iterator失效,只要在erase时,递增当前iterator即可。 对于序列式容器(如vector,deque),删除当前的iterator会使后面所有元素的iterator都失效。这是因为vetor,deque使用了连续分配的内存,删除一个元素导致后面所有的元素会向前移动一个位置。不过erase方法可以返回下一个有效的iterator,cont.erase(iter++)可以修改为cont.erase(iter) list使用了不连续分配的内存,并且它的erase方法也会返回下一个有效的iterator。 3. 下面我以Clang++编译器为例阐述一下C++继承模型的内存布局 对于多继承情况 考虑示例代码 1 2 3 struct Base1 {...}; struct Base2 {...}; struct Derived : Base1, Base2 {...}; 有如下内存布局 首先出现的是派生类Derived类的虚表指针vptr (这里插入一个提醒: 一直以来vptr都被国人翻译为虚函数表指针 但是vtbl英文原文是virtual table并非virtual function table 为什么呢

C++继承和多态

你说的曾经没有我的故事 提交于 2019-12-01 08:44:42
C++继承和多态 继承和派生 C++ 中的继承是类与类之间的关系, 继承(Inheritance) 可以理解为一个类从另一个类获取成员变量和成员函数的过程。 派生(Derive) 和继承是一个概念, 被继承的类称为父类或基类,继承的类称为子类或派生类。“子类”和“父类”通常放在一起称呼,“基类”和“派生类”通常放在一起称呼 当你创建的新类与现有的类相似 当你需要创建多个类,它们拥有很多相似的成员变量或成员函数时,使用继承。可以将这些类的共同成员提取出来,定义为基类,然后从基类继承 class Student: public People 继承的一般语法为: class 派生类名:[继承方式] 基类名{ 派生类新增加的成员 }; 继承方式: 包括 public(公有的)、private(私有的)和 protected(受保护的),此项是可选的,如果不写,那么默认为 private。 C++三种继承方式 继承方式 限定了基类成员在派生类中的访问权限,包括 public(公有的)、private(私有的)和 protected(受保护的)。此项是可选项,如果不写,默认为 private(成员变量和成员函数默认也是 private) public、protected、private 指定继承方式 1) public继承方式 基类中所有 public 成员在派生类中为 public 属性;

C++多态与虚函数

↘锁芯ラ 提交于 2019-12-01 08:43:50
C++多态与虚函数 面向对象程序设计语言有封装、继承和多态三种机制,这三种机制能够有效提高程序的可读性、可扩充性和可重用性。 “多态(polymorphism)”指的是同一名字的事物可以完成不同的功能。多态可以分为编译时的多态和运行时的多态 函数的 重载 ,对重载函数的调用,在编译时就能根据实参确定应该调用哪个函数,因此叫编译时的多态;后者则和继承、虚函数等概念是指运行时的多态。 #include <iostream> using namespace std; class People{ public: People(char *name, int age); void display(); protected: char *m_name; int m_age; }; People::People(char *name, int age): m_name(name), m_age(age){} void People::display(){ cout<<m_name<<"今年"<<m_age<<"岁了,是个无业游民。"<<endl; } //派生类Teacher class Teacher: public People{ public: Teacher(char *name, int age, int salary); void display(); private: int m

读书笔记《深度探索c++对象模型》(4) - 类函数语意

和自甴很熟 提交于 2019-12-01 05:00:21
一、类成员函数调用方式 非静态成员函数,要求非静态成员函数应与一般的非成员函数有相同执行效率,本质上,非静态的成员函数会被转为对等的非成员函数的实体( 即:非静态成员函数会被改写,加入 this 指针,并对函数内部的非静态成员变量的存取修改为由 this 指针来存取,最后将该函数重写为一个外部函数进行名称重命名,此时非静态成员函数与非成员函数别无二致了 )。 在非静态成员函数被重写为外部函数时的名称重命名操作,但此操作因不同的编译器实现不同,一般基于类名和函数参数类型、个数等来实现(为区分不同类重名成员变量、重载的非静态成员函数)(重命名操作,其实除了包括成员函数和虚函数外,静态成员函数也会被重命名)。 虚成员函数,因虚函数的存在,类中需增加一个 vptr 的指针,当然该指针名称也会被重命名以满足区分多继承时的多个 vptrs 。当通过对象或指针调用虚函数时,需先获取到虚指针再加上对一个虚函数所在的 slot 索引数字即可,即形如: (*ptr->vptr[someindex])(ptr)。 虚成员函数在通过指针对象调用虚函数和通过类对象调用虚函数的区别,前者可能需要通过(*ptr->vptr[someindex])(ptr)方式来调用,而后者可能直接用重名后的虚函数直接调用即可如:somefunc_XXX(&someobj)而不是(*obj.vptrsomeindex[(&obj

整理

牧云@^-^@ 提交于 2019-11-30 19:52:48
C++11 知识整理 对class的理解 答:首先,class 也是一种数据类型,只不过是可以由开发者自由定义的一种数据类型;可以用来封装成员变量和成员函数;支持抽象,继承,多态性;在定义数据类型的时候,private,public,也从一定程度上保证了数据的安全性 抽象性:含有纯虚函数的类被称为抽象类,用途是为派生类提供基类 多态性:对于不同对象接受相同信息时产生不同的动作。分为静态多态和动态多态,体现在两个方面,一是在编译的时候,函数重载是一个方面;二是在运行的时候,虚函数是一个方面 继承性:子类具有父类的各种属性和方法,而不必再次编写相同的代码 什么是类 答:一种将抽象转换成用于定义的类型的工具,将数据表示方法和操纵这些数据的方法组合一起整合成一个包 如何将私有成员变量取出 答:方法1:通过public中的函数,传出参数将私有成员变量取出。方法2:友元函数 *this 指针 答:经典回答,进入一个房间,能看见房间里的东西,但是整个房间看不到了,然后this指针就是时刻盯着这整个房间。this指针是类的一个自动生成,自动隐藏的私有成员。存在于类的非静态成员函数中,指向内调用函数所在的对象。全局仅有一个this指针,当一个对象被创建的时候,this指针就存放指向对象数据的首地址 类和对象的区别和联系 答:区别:(1).定义不同 ,类是现实世界或思维世界的实体在计算机的反映

static_cast与dynamic_cast转换

时间秒杀一切 提交于 2019-11-30 17:14:22
一 C 语言中存在着两种类型转换: 隐式转换和显式转换 隐式转换:不同数据类型之间赋值和运算,函数调用传递参数……编译器完成 char ch; int i = ch; 显示转换:在类型前增加 :(Type)变量 对变量进行的转换。用户显式增加 char *pc = ( char *)pb; void *ps = ( void *)pa; 二 C++ 中的类型转换   通过这两种方式,C语言中大部分的类型转换都可以顺利进行。 至于能不能进行转换,转换后的结果如何,编译器不管需要用户自己去控制。   C++继承了C中的隐式和显式转换的方式。但这种转换并不是安全和严格的, 加上C++本身对象模型的复杂性,C++增加了四个显示转换的关键字。(C++是强类型语言) ( static_cast , dynamic_cast , const_static , reinterpret_cast ) 1 static_cast (1 )用于基本的数据类型转换(char ,int ),及指针之间的转换 test_enum type = test_enum_1; char a ; int b = static_cast < int >(a); char c = static_cast < char >(b); type = static_cast <test_enum>(b); char * pa =

模板方法

佐手、 提交于 2019-11-30 16:33:11
重构的关键技法:   静态 -> 动态   早绑定 -> 晚绑定   继承 -> 组合   编译时依赖 -> 运行时依赖   紧耦合 -> 松耦合 "组件协作"模式   现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序间的松耦合,是二者之间协作时常用的模式。   典型模式:Template Method,Strategy,Observer/Event Template Method   动机:在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。   如何在确定稳定操作结构的前提下,来灵活地应对各个子步骤的变化或晚期实现需求。 要点总结:   Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简单的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。 绑定的概念   什么是绑定?     将函数体和函数调用关联起来,就叫绑定。   什么是早绑定?     在程序运行之前(也就是编译和链接时),执行的绑定是早绑定。   什么是晚绑定?     晚绑定发生在运行时,基于不同类型的对象。当一种语言实现晚绑定时

【C++】虚函数的实现机制

落花浮王杯 提交于 2019-11-30 16:15:38
一.什么是虚函数 ? 虚函数是在类中由virtual关键字声明的成员函数,并且每一个含有虚函数的类都至少有一个与之对应的虚函数表,其中存放着该类所有虚函数对应的函数指针 在基类中进行如下定义: virtual void show() //由于有virtual修饰所以是虚函数 void show()//虽然和前面声明的show虚函数同名,但不是虚函数 B的虚函数表中存放着B::foo和B::bar两个函数指针。 D的虚函数表中存放的既有 继承 自B的虚函数B::foo,又有 重写 (override)了基类虚函数B::bar的D::bar,还有 新增 的虚函数D::quz。 所有虚函数地址都会存放在所属类的虚函数表vtbl中,另外在基类中声明为虚函数的成员方法,达到子类是仍然是虚函数,即使子类中重新定义基类虚函数时未使用virtual修饰,该函数地址仍会放在子类的虚函数表vtbl中 二.虚函数表是如何构造和继承的? 1)基类虚函数表的构造: 首先在基类声明中找到所有虚函数,按照其声明顺序编码,然后按照此声明顺序为基类创建一个虚函数表,其内容就是指向这些虚函数的函数指针,按照虚函数声明的顺序将这些虚函数的地址填入虚函数表中,例如若show放在虚函数声明的第二位,则在虚函数表中也放第二位 2)子类虚函数表的构建和继承: 首先将基类的虚函数表复制到该子类的虚函数表指针中

C++的override和final

北战南征 提交于 2019-11-30 13:43:04
1、final用于让虚函数不可被重写 struct B2 { virtual void f() final {} // final 函数 }; struct D2 : B2 { virtual void f() {} }; 如上代码是不可被编译过的 2、override 1.在函数比较多的情况下可以提示读者某个函数重写了基类虚函数(表示这个虚函数是从基类继承,不是派生类自己定义的); 2.强制编译器检查某个函数是否重写基类虚函数,如果没有则报错。 来源: https://www.cnblogs.com/judes/p/11595365.html

Qt 中的二进制兼容策略(简而言之就是地址不能变,剩下的就是让地址不变的技巧)

时光毁灭记忆、已成空白 提交于 2019-11-30 13:38:22
本文翻译自 Policies/Binary Compatibility Issues With C++ 二进制兼容的定义 如果程序从一个以前版本的库动态链接到新版本的库之后,能够继续正常运行,而不需要重新编译,那么我们就说这个库是二进制兼容的。 如果一个程序需要重新编译来运行一个新版本的库,但是不需要对程序的源代码进一步的修改,这个库就是源代码兼容的。 二进制兼容性可以节省很多麻烦。这使得为特定平台分发软件变得更加容易。如果不确保版本之间的二进制兼容性,人们将被迫提供静态链接的二进制文件。静态二进制文件不好,因为它们 浪费资源(尤其是内存) 不能让程序从库中错误修正或扩展中受益 如何确保二进制兼容 在确保二进制兼容的情况下,我们能做的操作: 增加非虚函数、signal/slots、构造函数 增加枚举到类中 在已经存在的枚举的最后添加枚举值 例外:如果这会导致编译器为枚举选择更大的底层类型,那么更改会导致二进制不兼容。需要注意的是,编译器有选择基础类型的余地,所以从 API 设计的角度来看,建议添加一个 Max 枚举,其中包含一个明确的最大值(=255 或 =1 << 15 等)来创建一个数字枚举数值的区间,使其无论如何能够保证适合所选择的底层类型。 重新实现在父非虚基类 (从当前类回溯第一个非虚基类)里定义的虚函数,但是这个不完全确保二进制兼容,所以尽量不要这么做 例外: C++