带你走入虚函数和多态的世界(c++)

简介: 📖作者介绍:22级树莓人(计算机专业),热爱编程<目前在c++阶段>——目标Windows,MySQL,Qt,数据结构与算法,Linux,多线程,会持续分享学习成果和小项目的📖作者主页:热爱编程的小K📖专栏链接:c++🎉欢迎各位→点赞👏 + 收藏💞 + 留言🔔​💬总结:希望你看完之后,能对你有所帮助,不足请指正!共同学习交流 🐾————————————————版权声明:本文为CSDN博主「热爱编程的小K」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。原文链接:https://blog.csdn.net/qq_72157449

34a8468f5274473bb29996199832fa73.png

091033a765bd4518951a78df16895625.png

目录

1.什么是虚函数

C++类中用virtual修饰的函数叫做虚函数,构造函数没有虚构造函数,存在虚析构函数,C++所有虚函数都是一个指针去存储的,所以具有虚函数的类,内存会增加一个指针大小的内存

#include<iostream>

#include<string>

using namespace std;

class MM

{

public:

//虚函数指针是同一个,所以无论该类中有多少个虚函数,

//占用的内存就只是一个指针的大小

virtual void print()

{

 cout << "我是第一个虚函数" << endl;

}

virtual void printData()  

{

 cout << "我是第二个虚函数" << endl;

}

protected:

};

class son:public MM

{

public:

void print()  

{

 //该函数也是虚函数,

       //父类中同名函数是虚函数

 //所以子类该函数也是虚函数

}

protected:

};

int main()  

{

cout << sizeof(MM) << endl;

cout << "...................." << endl;

//虚函数表的理解,下面带图解

MM mm;

long long** p = (long long**)&mm;

using Func = void(*)();

Func f1 = (Func)p[0][0];

Func f2 = (Func)p[0][1];

f1();

f2();

return 0;

}

68f136481287487abdb2235af4cbd782.png

2.纯虚函数

  • 纯虚函数也是虚函数的一种,只是没有函数体,下面请看怎么表示没有函数体
  • 纯虚函数——>虚函数=0;
  • 具有一个或者多个虚函数的类叫做抽象类
  • 抽象类不能构建对象
  • 但是可以构建函数指针

#include<iostream>

using namespace std;

class MM

{

public:

virtual void print() = 0;

};

int main()

{

//MM mm; //抽象类不能构建对象

MM* pmm = nullptr;

return 0;

}

3.c++多态

多态指的是因为指针的不同的赋值操作所导致的同一行为的不同结果。多态的这个概念东西不太重要,重要的是什么样的情况调用什么样的行为

正常指针和正常对象调用行为,就近原则

父类指针被子类对象初始化

函数有virtual看对象类型

函数没有virtual看指针类型

final关键字 禁止子类重写父类方法

override显示说明当前函数是重写函数

多态三个必要性条件

1. 父类中存在虚函数

2. 存在不正常指针的引用(不正常赋值关系)

3. public继承

#include<iostream>

using namespace std;

class MM

{

public:

void print()

{

 cout << "父类" << endl;

}

virtual void printData()

{

 cout << "MM" << endl;

}

};

class son :public MM  

{

public:

void print()  

{

 cout << "子类" << endl;

}

void printData()  

{

 cout << "son" << endl;

}

};

int main()

{

MM* pmm = new son;

pmm->print();

pmm->printData();

return 0;

}

4.纯虚函数和ADT过程

ADT:abstract data type抽象数据类型,主要是通过继承抽象类中,子类必须要实现父类的抽象方法,子类才可以创建对象。

#include<iostream>

#include<string>

using namespace std;

class data

{

public:

string name;

int age;

};

class MM

{

public:

virtual bool empty() = 0;

virtual int size() = 0;

};

class List:public MM

{

public:

bool empty()

{

 return 0;

}

int size()

{

 return NULL;

}

};

int main()

{

MM* pmm = new List;

pmm->empty();

pmm->size();

}

5.虚析构函数

virtual修饰的析构函数就是虚析构函数,当存在子类对象初始化父类指针的时候,父类析构函数就要是虚析构函数,否则只会释放父类,存在内存泄漏问题

#include<iostream>

using namespace std;

class MM

{

public:

virtual ~MM()

{

 cout << "父类" << endl;

}

};

class son:public MM

{

public:

~son()

{

 cout << "子类" << endl;

}

};

int main()

{

MM* pmm = new son;

delete pmm;

return 0;

}

6.dynamic_cast类型转换

1. 上行转换 子类到父类 和staic_cast差不多
2. 下行转换 父类到子类 dynamic_cast更为安全
3. 交叉转换 多继承

#include<iostream>

using namespace std;

class MM

{

public:

virtual void print() { cout << "MM" << endl; }

};

class son:public MM

{

public:

void print() { cout << "son" << endl; }

};

class A

{

public:

virtual void print(){}

};

class B

{

public:

virtual void print() {}

};

class C:public A,public B

{

public:

void print()

{

 cout << "c" << endl;

}

};

int main()

{

MM* partent = new MM;

son* Son = new son;

//上行转换----->没有必要

MM* p = static_cast<MM*>(Son);

MM* pp = dynamic_cast<MM*>(Son);

MM* ppp = Son;       //可以

//下行转换

son* x = dynamic_cast<son*>(partent); //安全,父类没有virtual会报错---->多态

if(!x)

{

 printf("error");

}                           //下行转换不安全,不会申请成功

A* a = new A;

B* b = dynamic_cast<B*>(a);

b->print();

return 0;

}91dde779da5a45fcb8d6bc60eeec9054.png

7.成员函数指针

#include<iostream>

#include<functional>

using namespace std;

class MM

{

public:

void print() { cout << "king" << endl; }

static void printData() { cout << "MM" << endl; }

};

int main()

{

void(*p)() = &MM::printData;

p();

//必须通过对象调用

void(MM::*pp)() = &MM::print;

MM mm;

(mm.*pp)();

 

//函数适配器,让函数调用形态可以适用于别的形态

auto f = bind(&MM::print, &mm);

f();

return 0;

}

——————————————

版权声明:本文为CSDN博主「热爱编程的小K」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/qq_72157449/article/details/128699474

相关文章
|
虚拟化
虚拟机无法启动提示The virtual machine could not start. Make sure VMware Workstation is installed co
1、血案现场 The virtual machine could not start. Make sure VMware Workstation is installed correctly and you have rights to run the software and ...
1752 0
|
安全 物联网
萨姆萨拉(Samsara)推出全球首款采用Wi-Fi热点技术的智能手提箱
萨姆萨拉(Samsara)在CES上展示了其新一代智能行李箱。福布斯向在线观众爆料,称新产品线令人难以置信。评论继续说:“ Samsara是Away的竞争对手,不满足于将电池装在包中并称其为智能。”
500 0
萨姆萨拉(Samsara)推出全球首款采用Wi-Fi热点技术的智能手提箱
|
JavaScript Java Android开发
从eclipse到Android studio/迁移eclipse的Android项目到Android studio平台的注意事项
整体要注意的地方 先说明一下整体需要注意的地方 1在Android studio建立项目的时候,要注意包名和原来的完全一致,不然会有很多需要改动. 2依赖的jar一定一定要找齐,不然新建项目引用不到,要么重新找包,严重的话,那部分代码要重写,影响很恶劣.
1742 0
|
C++ C语言
NULL和NUL
① NULL: 定义为0或0L或(void *)0,用于指示一个指针值是空,即什么都不指; ② '\0': 用且只用字符串结束符,为字符常量; NUL是字符常量的名字; ③ NUL: 0x00,0值字符,用于结束ASCII字符串,和'\0'类似(可以理解为别名),但是在c/c++中没有定义,如果要使用的话,需要自定义为 #define NUL '\0'; EOF :通常定义为-1, 文件结束符标志,一般是ctrl+z. NULL是在头文件中专门为空指针定义的一个宏。
909 0
|
8月前
|
Python

热门文章

最新文章