虚函数

C++虚函数表解析

匿名 (未验证) 提交于 2019-12-03 00:34:01
C++中的虚函数的作用主要是实现了多态的机制。关于多态,简而言之就是用父类型别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可以让父类的指针有“多种形态”,这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。 关于虚函数的使用方法,我在这里不做过多的阐述。大家可以看看相关的C++的书籍。在这篇文章中,我只想从虚函数的实现机制上面为大家 一个清晰的剖析。 当然,相同的文章在网上也出现过一些了,但我总感觉这些文章不是很容易阅读,大段大段的代码,没有图片,没有详细的说明,没有比较,没有举一反三。不利于学习和阅读,所以这是我想写下这篇文章的原因。也希望大家多给我提意见。 言归正传,让我们一起进入虚函数的世界。 虚函数表 对C++ 了解的人都应该知道虚函数(Virtual Function)是通过一张虚函数表(Virtual Table)来实现的。简称为V-Table。 在这个表中,主是要一个类的虚函数的地址表,这张表解决了继承、覆盖的问题,保证其容真实反应实际的函数。这样,在有虚函数的类的实例中这个表被分配在了 这个实例的内存中,所以,当我们用父类的指针来操作一个子类的时候,这张虚函数表就显得由为重要了,它就像一个地图一样

虚函数与多态学习总结

匿名 (未验证) 提交于 2019-12-03 00:34:01
#include<iostream> using namespace std ; class Base { public : Base(char xx) { x = xx; } void who() { cout <<"Base class: " << x << "\n" ; } protected: char x; } ; class First_d : public Base { public : First_d(char xx, char yy):Base(xx) { y = yy; } void who() { cout <<"First derived class: "<< x << ", " << y<< "\n" ; } protected: char y; } ; class Second_d : public First_d { public : Second_d( char xx, char yy, char zz ) : First_d( xx, yy ) { z = zz; } void who() { cout <<"Second derived class: "<< x << ", " << y<< ", " << z << "\n" ; } protected: char z; } ; int main() { Base B_obj( 'A' ) ;

习题5

匿名 (未验证) 提交于 2019-12-03 00:33:02
C++的两种联编方式为: 静态 联编和 动态 联编。 C++支持两种多态性,静态联编所支持的多态性被称为 编译时的多态性 、动态联编所支持的多态性被称为 运行时的多态性 。 重载函数在编译时表现出多态性,就是 静态 联编;而虚函数则在运行时表现出多态性是 动态 联编。 为了区分重载函数,把一个派生类中重定义基类的虚函数称为 覆盖 。 如果派生类与基类的虚函数仅仅返回类型不同,其余相同,则C++认为是 使用不恰当的虚函数 。 在构造函数和析构函数中调用虚函数时,采用 静态 联编。 纯虚函数的定义是在虚函数定义的基础上,再让函数等于 0 。 对于包含有纯虚函数的类被称为 抽象类 。 用关键字( A )标记的函数被称为虚函数。 A. virtual B. private C. public D. protected 在C++中,要实现动态联编,必须使用( D )调用虚函数 A. 类名 B. 派生类指针 C. 对象名 D. 基类指针 下列函数中,可以作为虚函数的是( BD )。 A. 普通函数 B. 非静态成员函数 C. 构造函数 D. 析构函数 在派生类中,重载一个虚函数时,要求函数名、参数的个数、参数的类型、参数的顺序和函数的返回值( B )。 A. 不同 B. 相同 C. 相容 D. 部分相同 使用虚函数保证了在通过一个基类类型的指针(含引用)调用一个虚函数时,C++系统对该调用进行

C++PTA判断/选择题总结

匿名 (未验证) 提交于 2019-12-03 00:32:02
1-1 使用提取符(<<)可以输出各种基本数据类型的变量的值,也可以输出指针值。 (2分) T 1-2 预定义的插入符从键盘上接收数据是不带缓冲区的。 (2分) F 1-3 The cin stream normally is connected to the display screen. (2分) F 【cout 对象通常连接到标准输出设备,一般是显示屏】 2-1命名空间应用于: (2分) 在类外定义类的成员函数 √避免各个不同函数、变量等的名称冲突 提高代码的执行速度 以上答案都正确 2-2cout 是由I/O 流库预定义的( )。 (2分) 类 √对象 包含文件 常量 2-1 重载函数在 调用 时选择的依据中,错误的是()。 (2分) 函数的参数 参数的类型 函数的名字 √函数的类型 2-2 对定义重载函数的下列要求中,( )是错误的。 (2分) 要求参数的个数不同 要求参数中至少有一个类型不同 √要求函数的返回值不同 要求参数个数相同时,参数类型不同 1-1 函数的参数个数和类型都相同,只是返回值不同,这不是重载函数。 (1分) T 1-3The types of arguments in a function call must match the types of the corresponding parameters in the function

谭浩强《C++面向对象程序设计》知识点总结

匿名 (未验证) 提交于 2019-12-03 00:27:02
输入:采用标准输入流对象 istream 和提取运算符 cin>> 输出:采用标准输出流对象 ostream 和插入运算符 cout<< 一名多用,要求重载函数的参数个数或类型与原来的不同 给功能相似的函数建立一个统一的模板 要求:函数的参数个数和原来的要相同 格式: template <typename T> 通用函数定义 相当于给变量起一个别名,变量和其引用共享同一内存空间 e.g. int a; int &b = a; //声明b是一个int型变量a的引用 String类 格式: new 类型(初值) //返回一个指向数据类型的指针 new 类型[ num ] //new一个含有num个元素的类型数组 delete [ ] 指针变量 //[ ]表示对数组空间操作,可选 2.1 瀵硅薄 包含作为属性的数据成员和作为行为的成员函数,成员函数用来对数据进行操作,以便实现某些功能。 面向过程程序设计: 程序=数据结构+算法 面向对象程序设计: 对象=数据结构+算法, 程序=对象s+消息 抽象 :将有关事物归纳集中,作用是表示同一类事物的本质。类是对象的抽象,而对象是类的具体表现形式。 封装 :将数据和操作数据的函数绑定在一起,将具体的实现细节隐藏起来,仅对外保留接口。 继承 :利用已有类建立新类,新类从已有类中获得其意义特性的机制。 多态

C++虚函数

匿名 (未验证) 提交于 2019-12-03 00:22:01
众所周知,C++虚函数是一大难点,也是面试过程中必考部分。此次,从虚函数的相关概念、虚函数表、纯虚函数、再到虚继承等等跟虚函数相关部分,做一个比较细致的整理和复习。 虚函数 OOP的核心思想是多态性(polymorphism)。把具有继承关系的多个类型称为多态类型。引用或指针的静态类型与动态类型不同这一事实正是C++实现多态性的根本。 C++ 的多态实现即是通过虚函数。在C++中,基类将类型相关的函数与派生类不做改变直接继承的函数区别对待。对于某些函数,基类希望它的派生类各自定义适合自身的版本,此时基类就将这些函数声明为虚函数(virtual function)。 C++在使用基类的引用或指针调用一个虚函数成员函数时会执行动态绑定。因为只有直到运行时才能知道调用了那个版本的虚函数,所以 所有的虚函数必须有定义。 动态绑定只有当通过指针或引用调用虚函数时才会发生。 一旦某个函数被声明为虚函数,则在所有派生类中它都是虚函数。所以在派生类中可以再一次使用virtual指出,也可以不用。 如果某次函数调用使用了默认实参,则该实参值由本次调用的静态类型决定。换句话说,如果我们通过基类的引用或指针调用函数,则使用基类中定义的默认实参,即使实际运行的是派生类的函数版本也是如此。此时,传入派生类函数的将是基类函数定义的默认实参。 在某些情况下,我们希望对虚函数的调用不进行动态绑定

Spark 相关

匿名 (未验证) 提交于 2019-12-03 00:22:01
一、Spark SQL相关 1.spark sql 要比shark 快的几点: A.内存列存储,有点像parquet或者orc等列式存储格式,存储效率高 B.字节码生成技术,主要是避免了虚函数的调用,转变成了scala函数映射,在sql语句执行的时候,具体方法执行(例如 sort中的compare)会调用虚函数,虚函数调用会导致指令集预读失效,因为虚函数后面的指令集不是马上要执行的,导致cpu需要被暂停一下,这里给出相关的网址: Spark SQL Codegen介绍 C.scala代码优化 A:内存列存储(In-Memory Columnar Storage) B:字节码生成技术(bytecode generation,即CG) 复制代码 在这个查询里,如果采用通用的SQL语法途径去处理,会先生成一个表达式树(有两个节点的Add树,参考后面章节),在物理处理这个表达式树的时候,将会如图所示的7个步骤: 调用虚函数Add.eval(),需要确认Add两边的数据类型 调用虚函数a.eval(),需要确认a的数据类型 确定a的数据类型是Int,装箱 调用虚函数b.eval(),需要确认b的数据类型 确定b的数据类型是Int,装箱 调用Int类型的Add 返回装箱后的计算结果 其中多次涉及到虚函数的调用,虚函数的调用会打断CPU的正常流水线处理,减缓执行。 然后,通过调用,最终调用:

QLabel与图片的相互自适应

匿名 (未验证) 提交于 2019-12-03 00:20:01
//Label的大小自适应图片,Label随图片大小变化 QString bj (":/Resources/medalBtn/bj.png"); QImage image ; image.load(bj) ; ui->Label->setPixmap(QPixmap::fromImage(image)); ui->Label->resize(QSize(image.width(),image.height())); //图片的大小自适应Label,图片随Label的大小变化而变化,这种变化因窗口变化而比较复杂,以下为转载 转自: http://blog.csdn.net/wusiyuan163/article/details/51107574 最近因为项目的需要,需要在QLabel标签上显示图片。那么问题就来:1.图片如何自适应窗口控件的大小;2.图片如何随着窗口大小的改变而改变呢?这就是两个比较基本也最常见的问题了。 解决问题一:图片如何自适应窗口控件的大小? 相对于第一个问题,最初的想法的就是QLabel用布局进行管理,这样岂不就是固定了QLabel的大小,如何图片岂不也就是固定在QLabel里面,可是后来尝试了这种方法之后就呵呵(实践永远是真理)。虽然QLabel用布局管理了,但是当QLabel加载了图片以后,由于图片的大小问题,QLabel会压缩其他控件的位置

C++ 对象的内存布局

匿名 (未验证) 提交于 2019-12-03 00:18:01
http://www.jb51.net/article/101126.htm c++中一个类中无非有四种成员:静态数据成员和非静态数据成员,静态函数和非静态函数。 1、 非静态数据成员被放在每一个对象体内作为对象专有的数据成员。 2、 静态数据成员被提取出来放在程序的静态数据区内,为该类所有对象共享,因此只存在一份。 3、 静态和非静态成员函数最终都被提取出来放在程序的代码段中并为该类所有对象共享,因此每一个成员函数也只能存在一份代码实体。在c++中类的成员函数都是保存在静态存储区中的 ,那静态函数也是保存在静态存储区中的,他们都是在类中保存同一个惫份。 因此, 构成对象本身的只有数据 ,任何成员函数都不隶属于任何一个对象,非静态成员函数与对象的关系就是绑定,绑定的中介就是this指针。成员函数为该类所有对象共享,不仅是处于简化语言实现、节省存储的目的,而且是为了使同类对象有一致的行为。同类对象的行为虽然一致,但是操作不同的数据成员。 #include"iostream.h" class A { private : int x; int y; public : void sety() { y=5; } void print() { cout<< "x=" <<x<<endl<< "y=" <<y<<endl; } }; void main() { A a; a.sety(); a

C++构造函数和析构函数调用虚函数时都不会使用动态联编

匿名 (未验证) 提交于 2019-12-03 00:06:01
可以,虚函数底层实现原理(但是最好不要在构造和析构函数中调用) 可以,但是没有动态绑定的效果,父类构造函数中调用的仍然是父类版本的函数,子类中调用的仍然是子类版本的函数。 effictive c++第九条,绝不在构造和析构过程中调用virtual,因为构造函数中的base的虚函数不会下降到derived上。而是直接调用base类的虚函数。绝不在构造和析构函数中调用virtual函数: a) 如果有继承,构造函数会先调用父类构造函数,而如果构造函数中有虚函数,此时子类还没有构造,所以此时的对象还是父类的,不会触发多态。更容易记的是基类构造期间,virtual函数不是virtual函数。 b) 析构函数也是一样,子类先进行析构,这时,如果有virtual函数的话,子类的内容已经被析构了,C++会视其父类,执行父类的virtual函数。 c) 总之,在构造和析构函数中,不要用虚函数。如果必须用,那么分离出一个Init函数和一个close函数,实现相关功能即可。 原文链接:https://blog.csdn.net/chen134225/article/details/81564972 第一个理由是概念上的。 在概念上,构造函数的工作是生成一个对象。在任何构造函数中,可能只是部分形成对象――我们只能知道基类已被初始化,但并不能知道哪个类是从这个基类继承来的。然而,虚函数在继承层次上是“向前