虚函数

C++笔记(3):一些C++的基础知识点

99封情书 提交于 2020-02-26 23:05:08
前言: 找工作需要,最近看了下一些C++的基本概念,为范磊的 《零起点学通C++》,以下是一些笔记。 内容:   delete p;只是删除指针p指向内存区,并不是删除指针p,所以p还是可以用的。删除空指针所指向内存是可以的。   堆中的变量和对象时匿名的,没有名称,只能通过指针来访问。   在堆中创建对象时,在分配内存的同时会调用类的构造函数,在删除堆中对象时,会调用类的析构函数。   为了避免内存泄露,在删除一个指针后应该将其其值赋为0。   常量指针是指针指向的内存区域地址不能改变,但是该内存地址里保存的值是可以改变的,比如int a; int * const p = &a;   指向常量的指针表示指针指向的对象是不能被修改的,但是该指针可以被修改,即该指针可以指向另一块目标内存地址。比如const int a = 0; const int *p = &a; 如果A是一个类,也可以为const A* p = new A;   而指向常量的常指针表示指针本身不能被修改,其指向的内存地址内容也不能被修改。比如const int a = 0; const int * const p = &a;   引用就是别名常量。   堆中的地址是用指针来操作的,用不到别名。   如果在main函数前面的其它函数的声明和定义是一起的,则表明这个函数是内联函数!因此当该函数较长时

Interview_C++_day15

怎甘沉沦 提交于 2020-02-22 19:43:52
开始刷C++部分面经 虚函数表、虚函数指针内存位置 虚函数表存储在常量区,也就是只读数据段 虚函数指针存储在对象内。 使用宏定义求结构体成员偏移量 #include<bits/stdc++.h> #define offsetof(TYPE, MEMBER) ((size_t) &((TYPE*)0)->MEMBER) /* (TYPE*)0 将零转型成 TYPE 类型指针 ((TYPE*)0->MEMBER) 访问结构体中的成员 &((TYPE*)0->MEMBER) 取出数据成员地址,也就是相对于零的偏移量 (size_t) & ((TYPE*)0)->MEMBER) 将结果转换成 size_t 类型。 */ struct Node { char a; short b; double c; int d; }; int main() { printf("%d\n", offsetof(Node, a)); printf("%d\n", offsetof(Node, b)); printf("%d\n", offsetof(Node, c)); printf("%d\n", offsetof(Node, d)); return 0; } \(size\_t\) 在可以理解成 \(unsigned\ \ int\) ,在不同平台下被 \(typedef\) 成不同类型。 \(C\) +

C++ 常见面试题目

送分小仙女□ 提交于 2020-02-21 07:05:14
const作用 (1)可以定义const常量,具有不可变性。 (2)便于进行类型检查。(而宏不会进行类型检查)。 (3)可以保护被修饰的东西,防止意外的修改。 (4) 可以节省空间。 static作用 1.隐藏:一个文件中的全局变量在另外一个文件中使用extern声明就能使用,声明了static就不能了 一个函数内的static变量具有全局生命期,但只在这个函数中可见 2.记忆功能和全局生存期 3.默认初始化为0 4.类的静态成员函数是属于整个类而非类的对象,所以它没有this指针 5.不能将静态成员函数定义为虚函数。 6.不可以同时用const和static修饰成员函数。 什么函数不能声明为虚函数 1:只有类的成员函数才能说明为虚函数; 2:静态成员函数不能是虚函数; 3:内联函数不能为虚函数; 4:构造函数不能是虚函数; 5:析构函数可以是虚函数,而且通常声明为虚函数。 指针和引用的区别 本质上:指针是一个新的变量,只是这个变量存储的是另一个变量的地址,我们通过访问这个地址来修改变量。 而引用只是一个别名,还是变量本身。对引用进行的任何操作就是对变量本身进行操作,因此以达到修改变量的目的。 1.引用必须被初始化,指针不必 2.引用初始化以后不能被改变,指针可以改变所指的对象。 3.不存在指向空值的引用,但是存在指向空值的指针。 4."sizeof引用"得到的是所指向的变量(对象

C++ 虚函数表

二次信任 提交于 2020-02-20 13:34:53
当通过指针访问类的成员函数时: 如果该函数是非虚函数:编译器会根据指针的类型找到该函数。 如果该函数是虚函数,并且派生类有同名的函数遮蔽它:编译器会根据指针的指向找到该函数,这就是多态。 对象的内存模型是非常干净的,没有包含任何成员函数的信息,编译器究竟是根据什么找到了成员函数呢? 编译器之所以能通过指针指向的对象找到虚函数,是因为在创建对象时额外的增加了虚函数表 虚函数表(vtable) 如果一个类包含了虚函数,那么在创建该类的对象时就会额外的增加一个数组,数组中每一个元素都是虚函数的入口地址。 不过数组和对象是分开存储的,为了将对象和数组关联起来,编译器还要再对象中安插一个指针,指向数组的起始位置。 这里的数组就是虚函数表。 #include <iostream> #include <string> using namespace std; //People类 class People{ public: People(string name, int age); //构造函数 public: virtual void display(); virtual void eating(); protected: string m_name; int m_age; }; People::People(string name, int age): m_name(name), m_age

c++复习 多态

偶尔善良 提交于 2020-02-19 00:55:27
虚函数 什么是虚函数? 指向基类的指针在操作它的多态类对象时,会根据不同的类对象调用其相应的函数,这个函数就是虚函数,用virtaul修饰函数名。 虚函数的作用是在程序运行阶段动态地选择合适的成员函数 在派生类中重新定义的函数应与虚函数具有相同的形参个数和形参类型,(参数顺序也要一致),以实现统一接口, 如果派生类中没有重新定义虚函数,则它集成基类的虚函数 虚函数的重写 虚函数的重写:派生类中有一个跟基类的完全相同虚函数,我们就称子类的虚函数重写了基类的虚函数,完全相同是指:函数名、参数、返回值都相同。另外虚函数的重写也叫作虚函数的覆盖。 class Person { public : virtual void BuyTicket ( ) { cout << "买票-全价" << endl ; } } ; class Student : public Person { public : virtual void BuyTicket ( ) { cout << "买票-半价" << endl ; } } ; void Func ( Person & p ) { p . BuyTicket ( ) ; } int main ( ) { Person ps ; Student st ; Func ( ps ) ; Func ( st ) ; return 0 ; } 不规范的重写行为

我的大厂面试经历

被刻印的时光 ゝ 提交于 2020-02-17 17:31:41
2020-02-17 10:53:03 在这里提供一下自己复习的东西吧,我也就把这个东西给搞了一遍,然后面试基本没啥问题了,如果问的很深的话,那就只能只求多福了兄弟!其中可能有一些错误或者由于编译环境有差异请大家自动忽略这些错误。 1:信号的生命周期? 信号产生-》信号在进程中注册-》信号在进程中的注销-》执行信号处理函数 2:信号的产生方式? (1)当用户按某些终端键时产生信号(2)硬件异常产生信号【内存非法访问】(3)软件异常产生信号【某一个条件达到时】(4)调用kill函数产生信号【接受和发送的所有者必须相同,或者发送的进程所有者必须为超级用户】(5)运行kill命令产生信号 3:信号处理方式? (1)执行默认处理方式(2)忽略处理(3)执行用户自定义的函数 4:如何消除隐式转换? 使用explicit关键字进行修饰 5:重载,重写和隐藏的区别? 重载:即函数重载 重写【覆盖】:即用于虚函数 隐藏:只要派生类的函数名与基类相同就会隐藏 6:volatile表示什么?有什么作用? 易变的,不会被编译器进行优化,让程序取数据直接去内存中的。 7:Static_cast<>,dynamic_cast<>,const_cast<>,reinterpret_cast<>的各自作用和使用环境? Static_cast:能完成大部分转换功能,但是并不确保安全 Const_cast

C++纯虚函数和抽象类

蓝咒 提交于 2020-02-16 22:03:05
  在C++中,可以将虚函数声明为纯虚函数,语法格式为: virtual 返回值类型 函数名 (函数参数) = 0; 纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上 =0 ,表明此函数为纯虚函数。最后的 =0 并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。 包含纯虚函数的类称为抽象类(Abstract Class) 。之所以说它抽象,是因为它无法实例化,即无法创建对象。因为纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。   抽象类通常是作为基类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化。派生类可以只实现抽象基类中的某一个纯虚函数,此时该派生类对象还不能实例化(该派生类仍是抽象类),必须是所有纯虚函数都在派生类中实现才可以实例化。   抽象基类不需要被实例化,但是它为派生类提供了“约束条件”,派生类必须要实现抽象基类中的纯虚函数,完成对应的功能,否则就不能实例化。抽象基类除了约束派生类的功能,还可以实现多态。   一个纯虚函数就可以使类成为抽象基类,但是抽象基类中除了包含纯虚函数外,还可以包含其它的成员函数(虚函数或普通函数)和成员变量。只有类中的虚函数才能被声明为纯虚函数,普通成员函数和顶层函数均不能声明为纯虚函数。如下: 1 //顶层函数不能被声明为纯虚函数 2 void fun() = 0; /

C++虚函数汇总

不打扰是莪最后的温柔 提交于 2020-02-16 19:03:44
关于C++虚函数,主要是服务于多态,但里面一些细节的点还是很多的,我总结一下我目前所遇到的基本重要的几点,通过一下几个方面讲解: 虚函数的介绍 那些函数可以设为虚函数?那些函数不行? 纯虚函数 虚函数的介绍: 虚函数 说白了就是成员函数前加上 virtual ,虚函数主要实现多态,对多态访问父类函数方法进行操作。但是在这里有一个细节性的问题:虚函数是如何实现子类访问父类的函数的呢? 这里我们要知道一个叫 虚函数表 的概念,当我们书写一个类,给类的成员函数加上virtual后,这个类的大小就会相比较没有加virtual时,多了四个字节。 例子: class Base { public: virtual void func(); private: int ma; int mb; }; 大家可以在VS的代码源目录文件中,键入命令: /d1reportSingleClassLayout 查看想要查看的类: 可以看到,多了一个叫vfptr的指针,占四个字节,而这个指针就是指向虚函数表,所谓虚函数表,就是存放了你设计的虚函数的地址,这也就能解释了,为什么子类可以访问父类的函数,就是通过虚函数指针,访问了虚函数表中函数。 这里要注意一点:如果子类也定义了一个虚函数并且与父类的同名,那么虚函数表中的函数就会把父类的虚函数地址替换成子类的。 关于 虚函数表 :虚函数表是在编译阶段生成的

C++多态

青春壹個敷衍的年華 提交于 2020-02-16 09:51:28
1概念 多态 :不同类型对象调用相同接口完成不同的行为。 1.1覆盖(重写override)成立的三个条件 1.继承 2.子类覆盖(重写)父类虚函数 3.父类指针/引用指向子类 1.2虚函数定义规则: 如果虚函数在基类与派生类中出现,仅仅是名字相同,而形式参数不同,或者是返回类型不同,有无const. 那么 即使加上了virtual关键字,也是不会覆盖。 只有 类的成员函数才能说明为虚函数 ,因为虚函数 仅适合 用与有继承关系的类对象,所以普通函数不能说明为虚函数。 静态成员函数不能是虚函数 ,因为静态成员函数的特点是不受限制于某个对象。 内联(inline)函数不能是虚函数 ,因为内联函数不能在运行中动态确定位置。即使虚函数在类的内部定义,但是在编译的时候系统仍然将它看做是非内联的。 构造函数不能是虚函数 ,因为构造的时候,对象还是一片未定型的空间,只有构造完成后,对象才是具体类的实例。 析构函数可以是虚函数 ,而且通常声明为虚函数。 1.3多态的实现原理分析 当类中声明虚函数时,编译器会在类中生成一个 虚函数表(基类和派生类中各自都会生成一个) 1.4虚函数表 虚函数表是一个 存储类成员函数指针 的数据结构 虚函数表是由 编译器自动生成和维护 的 virtual函数会被 编译器 放入虚函数表中 存在虚函数时,每个对象当中都有一个 指向虚函数表的指针 (vptr指针) 1

C++中的类型识别

你。 提交于 2020-02-16 01:14:58
文章目录 1 C++中的类型识别 1.1 类型识别的基本概念 1.2 利用多态得到动态类型 1.3 typeid关键字 1 C++中的类型识别 1.1 类型识别的基本概念 在面向对象中可能出现下面的情况: 基类指针指向子类对象。 基类引用成为子类对象的别名。 静态类型和动态类型的概念: 静态类型:变量(对象)自身的类型。 动态类型:指针(引用)所指向对象的实际类型。 1.2 利用多态得到动态类型 利用多态得到动态类型: 在基类中定义虚函数返回具体的类型信息。 所有的派生类都必须实现类型相关的虚函数。 每个类中的类型虚函数都需要不同的实现。 编程实验:动态类型识别 # include <iostream> # include <string> using namespace std ; class Base { public : virtual string type ( ) { return "Base" ; } } ; class Derived : public Base { public : string type ( ) { return "Derived" ; } void printf ( ) { cout << "I'm a Derived." << endl ; } } ; class Child : public Base { public : string