C++:继承和多态

虚函数:只有类的成员函数才能定义为虚函数

虚函数 在类的成员函数前面加上一个 virtual 关键字, 此时这个成员函数就叫做虚函数
虚函数 当在子类中定义了一个与父类完全相同的虚函数的时候,此时就叫做子类的虚函数重写了父类的虚函数
构成多态的条件 派生类重写基类的虚函数实现多态, 必须要求函数名相同参数列表以及返回值相同(协变除外)
协变 派生类重写基类的虚函数的时候函数名相同, 参数列表相同, 但是返回值可以不同(返回值是父子关系)

静态成员函数不能定义为虚函数

静态成员函数是属于这个类的, 它不属于某个对象, 而虚函数必须有一张虚表, 但是虚表存在于对象中,静态成员函数既然不属于对象,那么何来的虚表呢, 没有虚表又何谈虚函数呢
类外定义虚函数 只能在声明虚函数的时候在虚函数前面加上一个 virtual 关键字, 当在类外定义的时候, 此时就不能在其前面加上 virtual 关键字

构造函数 构造函数不能为虚函数.

原因是虚函数必须有一张虚表, 但是虚表又存在于对象中, 那么问题来了, 构造函数是为了构造出对象的, 现在对象都没有, 拿来的虚表, 没有虚表拿来的虚函数

父类是虚函数,子类会继续保持,反之不成立

不要在析构函数或者构造函数中调用虚函数

因为在构造函数和析构函数中对象会不完整, 而虚函数的前提是存在于虚表中, 虚表又存在于对象中, 对象不完整,如何找到虚函数呢

最好把基类的析构函数声明为虚函数

class Person
{...
};class Student:public Person
{...
};int main()
{Person* p = new Student;delete p;return 0;
}

看到上面的场景中, 我们第一反应就是当我们一次New, 一次delete没有任何问题, 但是问题来了, 如果Student中除了普通成员函数外, Student 对象在析构的时候还需要我们自己去清理, 此时delete的只是父类的对象, 那student中需要清理的内存没有得到清理,此时不就造成内存泄露了吗?
同时注意, 子类和父类的析构函数在编译的时候编译器会将两者处理为相同函数名, 因此当定义为虚函数的时候,此时关注的就是对象了, 在释放的时候会看一下p是一个student的对象,因此会清理student中的东西,此时就不会造成内存泄露了
将析构函数定义为虚函数的目的就是为了在析构的时候当对象是子类的时候清理子类,当对象是父类的时候清理父类,已达到资源正确释放

多态:虚函数指针或引用+父类指针或引用

多态条件
当使用基类指针或者引用调用重写的虚函数的时候,此时指向父类调用的就是父类的虚函数,指向子类调用的就是子类的虚函数

为什么指针和引用可以实现多态而对象不能实现多态

class A
{
public:virtual void Debug(){}
};class B:public A
{
public:virtual void Debug(){}
};void main()
{B b;A a = b;A * point_A = &b;a.Debug();point_A->Debug();
}

——对于程序A a = b而言,b内存布局在赋值的时候已经从B转换到A了,多于的数据都被丢弃,因此其就是一个A类型变量,那么a.Debug这里的a就是一个A类型的变量。
——对于point_A来说,它是一个指针,其类型虽然是A,但指向的区域的内容却是一个B类型的内存结构,虽然内存结果的布局与A兼容,但其虚函数表中的Debug却是B的实现。

内联函数不能定义为虚函数

虚函数必须有虚表,虚表中存放的是地址,但是内联在编译的过程中会被展开,它没有地址何来的虚表,没有虚表何来的虚函数

调用普通函数比调用虚函数快

因为普通函数就是直接call到一个地址,而调用虚函数得先找到虚表, 然后拿着虚表中的地址再找到虚函数, 因此虚函数是间接寻址, 多了访存次数, 当然也就比普通函数慢了

重写重载重定义的区别

重载 重载函数必须在同一作用域内,满足函数名相同, 参数不同的函数就叫做函数之间构成了重载
重写(覆盖)不同作用域内(基类和派生类)函数名相同, 参数相同, 返回值相同(协变除外), 同时函数前必须有 virtual 修饰
重定义(隐藏) 不同作用域内(基类和派生类)函数名相同, 只要不是重写就是重定义

继承与静态函数

基类中定义了static成员, 则整个继承体系中只有一个static成员, 无论派生出多少个子类, 都只有一个static成员实例

纯虚函数

成员函数形参后面加上 = 0, 此时的成员函数就会变成纯虚函数. 同时包含纯虚函数的类就叫做抽象类(接口类)
纯虚函数只有在派生类中重新定义后才能实例化出对象
抽象类不能实例化出对象

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/383900.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

POJ 1061扩展欧几里得

扩展欧几里得的模板题&#xff0c;需要注意的是为了得到一个最小正数解我们要使axbyc中的a,b都是正数 #include<cstdio> #include<cstring> #include<cstdlib> #include<algorithm> #include<iostream> #include<cmath> #include<ctim…

C++::探索对象模型

前面我们已经知道, 在没有虚函数的时候, 对象的大小就是对应的成员变量的大小, 而成员函数不会占用对象的空间, 今天我们来讨论一下, 当类中定义了虚函数的时候, 此时对象的大小以及对象模型 非继承下的对象模型 class Base { public:virtual void func1(){cout << &qu…

auto_ptr

#include <iostream> #include <memory> using namespace std;class A { public:A(){cout<<"构造"<<endl;}~A(){cout<<"A析构"<<endl;}void fun(){cout<<"A::fun"<<endl;} };class PA { public…

POJ 2142——扩展欧几里得

题目是很裸的扩展欧几里得&#xff0c;但是对x,y有限制条件&#xff0c;要求所有x,y中abs(x)abs(y)最小&#xff0c;在这个条件下要求abs(a* x)abs(b* y)最小 显然我们需要用扩展欧几里得求得一组解&#xff0c;问题在于如何处理这组解以得到符合条件的值。 我是这样处理的&a…

C++::模板

模板的简单介绍 C中模板是为了能够使得函数或者类实现范型编程的目的, 同时C模板的出现是为了避免代码的冗余 举个例子 void Swap(int& a, int& b) {int tmp a;b a;a b; } void Swap(char& a, char& b) {char tmp a;b a;a b; } 上面的函数除了类型不…

Linux select TCP并发服务器与客户端编程

http://blog.csdn.net/szkbsgy/article/details/10558881 [cpp] view plaincopy <span style"font-size:18px;">服务端&#xff1a; #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/time.h> #i…

BZOJ - 2186 欧拉函数

题目的意思大概是求1~N!中和M&#xff01;互质的数的个数 因为对欧拉函数理解不够深刻所以我是分析得到结果的&#xff1a; 当N<M的时候显然符合要求的数的个数为0&#xff1b; 当N>M的时候我们要求的是1~N!中不含1 ~M的素因子的的数的个数&#xff0c;结合欧拉函数的…

多态相关概念

多态相关注意事项 所谓的多态就是指函数有多中状态, 在C中通常是通过父类指针指向子类对象的方法实现多态, 这样父类可以通过子类的类型调用不同的方法. 即实现一个接口多种方法, 多态的引用是为了实现接口复用 在 C中多态是通过虚函数来实现的. 子类通过对父类相关接口进行重…

模板实现栈队列以及链表

模板实现链表 //test.h #include <iostream> #include <cstdio> #include <assert.h> using namespace std;template <class T> struct ListNode {ListNode* _prev;ListNode* _next;T _data;ListNode(const T& x):_prev(NULL),_next(NULL),_data(…

基于Visual C++2013拆解世界五百强面试题--题5-自己实现strstr

http://blog.csdn.net/itcastcpp/article/details/12907371 请用C语言实现字符串的查找函数strstr&#xff0c; 找到则返回子字符串的地址&#xff0c;没有找到返回为空&#xff0c;请用数组操作与指针操作实现 看到题目想到最简单的方法就是母字符串和子字符串比较&#xff0c…

卡特兰数

卡特兰数的引入与n边形分成三角形的个数有关&#xff1a; 我们令f[n]表示n边形可以分成的三角形的个数&#xff0c;特殊的&#xff0c;令f[2]1 我们考虑以顶点1顶点的一个三角形&#xff0c;假设用的是n边形的k-k1边&#xff0c;那么这种情况的方案数就是f[k]∗f[n−k1]f[k]*…

软件测试相关概念

什么叫软件测试 软件测试就是测试产品没有错误,同时又证明软件是可以正确运行的 测试和调试的区别 调试一般都在开发期间 ,测试是伴随着整个软件的生命周期, 调试是发现程序中问题并且解决问题, 测试是发现程序中的缺陷 软件测试的目的和原则 目的:验证软件有没有问题 原…

Linux 线程信号量同步

https://www.cnblogs.com/jiqingwu/p/linux_semaphore_example.html 信号量和互斥锁(mutex)的区别&#xff1a;互斥锁只允许一个线程进入临界区&#xff0c;而信号量允许多个线程同时进入临界区。 不多做解释&#xff0c;要使用信号量同步&#xff0c;需要包含头文件semaphore.…

本原勾股数组

勾股数我们都很熟悉&#xff0c;a2b2c2&#xff0c;可是如何快速找到所有的勾股数组呢&#xff1f; 本原勾股数组a2b2c2性质&#xff1a; 1. a,b奇偶不同&#xff0c;c一定是奇数 2. 若b为偶数&#xff0c;c-b和cb一定是完全平方数 3. 设t>s>1,且均为奇数&#xff0c;则…

C++静态成员函数访问非静态成员的几种方法

https://www.cnblogs.com/rickyk/p/4238380.html 大家都知道C中类的成员函数默认都提供了this指针&#xff0c;在非静态成员函数中当你调用函数的时候&#xff0c;编译器都会“自动”帮你把这个this指针加到函数形参里去。当然在C灵活性下面&#xff0c;类还具备了静态成员和静…

费马大定理

当n>3时方程 xnynzn没有正整数解 结论很简洁&#xff0c;刚才看了一下证明的历史&#xff0c;我勒个去。。。。

类中的静态成员函数访问非静态成员变量

http://blog.csdn.net/u011857683/article/details/52294353 1.思路&#xff1a; 静态成员函数属于类(通过类访问&#xff0c;调用函数时没有提供this指针)&#xff0c; 非静态成员函数属于实例&#xff08;通过对象访问&#xff09;&#xff08;默认都提供了this指针&#xf…

Pollar Rho算法

原本是想把这个算法搞懂的&#xff0c;然后在网上看了又看&#xff0c;觉得&#xff0c;还是有时间再来看吧&#xff0c;我错了。 看到了一个大佬的博客&#xff0c;顺带收集一下板子 这个板子可以求大数的最大的因子。 #define LL long long bool IsPrime(LL);//返回素性测…

小知识点总结

用户输入一个url之后到整个页面返回给客户这个过程都经历了一些什么 首先url是为了让人记忆方便的,计算机在进行网络传输的过程中只能通过ip地址找到对应的主机,所以当输入一个ip地址的时候,此时就需要找对应的url,首先从浏览器中取查找ip地址,再到系统中去查找,再到域名解析服…

C++学习之普通函数指针与成员函数指针

http://blog.csdn.net/lisonglisonglisong/article/details/38353863 函数指针&#xff08;function pointer&#xff09;是通过指向函数的指针间接调用函数。相信很多人对指向一般函数的函数指针使用的比较多&#xff0c;而对指向类成员函数的函数指针则比较陌生。我最近也被问…