2024年Python最全C++基础语法----多态,在字节跳动我是如何当面试官的

文末有福利领取哦~

👉一、Python所有方向的学习路线

Python所有方向的技术点做的整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。img

👉二、Python必备开发工具

img
👉三、Python视频合集

观看零基础学习视频,看视频学习是最快捷也是最有效果的方式,跟着视频中老师的思路,从基础到深入,还是很容易入门的。
img

👉 四、实战案例

光学理论是没用的,要学会跟着一起敲,要动手实操,才能将自己的所学运用到实际当中去,这时候可以搞点实战案例来学习。(文末领读者福利)
img

👉五、Python练习题

检查学习结果。
img

👉六、面试资料

我们学习Python必然是为了找到高薪的工作,下面这些面试题是来自阿里、腾讯、字节等一线互联网大厂最新的面试资料,并且有阿里大佬给出了权威的解答,刷完这一套面试资料相信大家都能找到满意的工作。
img

img

👉因篇幅有限,仅展示部分资料,这份完整版的Python全套学习资料已经上传

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

}

void print() {

cout << “我是Diren” << endl;

}

};

void zhanzheng(OUr* p, Diren& a) {

if (p->get() > a.get()) {

cout << “我们将敌人秒杀了” << endl;

}

else {

cout << “我们败北” << endl;

}

}

int main_02() {

OUr * p;

him friends;

me zsc;

Diren DDD;

p = &friends;

zhanzheng(p,DDD);

p = &zsc;

zhanzheng(p, DDD);

p->print();//打印基类的print函数;

return 0;

}

三、多态实现行为分析

============================================================================

1.函数重载、重写、重定义


①函数重载:

发生在一个类,名字相同参数类型或个数不同;

②函数重写:

子类继承父类,子类中写了一个与父类名称相同,参数列表也相同的函数;

剖析函数重写:

多态: 如果使用了virtual关键字,那么就构成多态;

多态在运行时根据所给的对象类型选择调用的函数;

③函数重定义:

举个例子:基类有两个打印函数print(),与print(int a);这两个函数构成重载;

子类中定义了一个函数,名字也叫print参数无所谓,此时子类就将父类的print重定义(覆盖掉);

比如子类定义了一个print(),那么他将无法调用起来父类的print(int a),与print();

与virtual关键字无关,此时说的对象是子类的对象,virtual对应的是基类指针

⚠️重写纯虚函数可以产生多态;

⚠️重写普通函数可以产生重定义;(不加virtual关键字)重定义之后就无法再通过子类的对象调用父类的函数

2.虚析构函数与虚构造函数


①构造函数能不能定义成为虚的?

不能,virtual定义虚函数为了多态;

构造函数是在对象初始化期间自动调用的,不需要手动的调动更不用产生多态;

将构造函数定义为虚函数没有什么实际意义

②为什么要用虚析构函数?

我们知道virtual关键字主要实现动态绑定

如果不使用虚构造函数,在析构对象时会与调用函数时的效果一样;

只调用基类的析构函数;而此时子类未被析构会造成内存泄漏

用virtual关键字对析构函数处理,会产生多态,在运行时,根据析

构的对象是什么类的类型合理调用析构函数;

③怎么使用虚析构函数?

在析构函数面前加上virtual

具体如下:

#include

using namespace std;

class testa {

public:

testa(int a) {

this->a = a;

}

int a;

virtual ~testa(){

cout << “欧式爸爸析构函数” << endl;

}

};

class testb :public testa{

public:

testb(int b):testa(b) {

this->b = b;

}

int b;

~testb() {

cout << “欧式孩子析构函数” << endl;

}

};

void howTodel(testa *p) {

if (p != NULL) {

delete p;//delete要与new或者malloc搭配,不能直接释放编译器自动分配的内存;

}

}

int main_04() {

testa* p = new testa (1);

testa* q = new testb(1);//子类函数中有基类的属性

howTodel§;//如果不加virtual则与普通函数一样只会调基类的析构函数;

howTodel(q);//子类的对象得不到析构,可能会引发内存泄漏,解决方法就是在析构函数前加virtual;

return 0;

}

四、多态实现原理剖析

============================================================================

1.理论基础


c与c++语言是静态编译型语言;

在程序未运行之前编译器就将代码串联在一起(什么时候运行哪一步);

基类指针可以指向子类对象,但是编译器进行静态编联时不清楚基类指针到底指向谁,

此时编译器判定:基类指针是基类的类型,又由于程序未运行为了安全起见编译器就

将基类指针指向了基类的对象;

动态联编:在运行时编译器根据代码运行的效果选择如何进行后续的操作;

eg:

if语句 switch语句

virtual关键字起到的作用是告诉编译器,这个函数要支持多态,不要根据他

指针的类型判断如何调用他;

2.实现原理


①为什么在函数声明时加了virtual会发生多态?

是在函数声明时在函数前加上的virtual 会将该函数拿到此类对应的虚函数表,

并拿一个vptr指针指向该虚函数表。

vptr指针与基类的指针指向的对象相对应;

(基类的指针指向什么类的对象, vptr指针就指向什么类的虚函数表)

而此时vptr指针与this指针相似,程序员并看不到;

所以在调用虚函数时,根据基类指针指向对象的vptr指针的类型在对

应的虚函数表中找到函数入口,由此发生多态;

②怎样证明vptr指针的存在?

设置两个相同的类,属性与方法也相同,在某个函数前加上virtual类的大小会增加4;

继续增加基类中的含有virtual函数类的大小还会不会增加?

不会,类的大小只会增加一次,增加的那一次就是将带有virtual的指针指向虚函数表,

将虚函数拿到虚函数表;再用virtual声明函数时直接将函数拿到虚函数表,所以不会再增加;

(函数平时存在代码区,不占类的大小);

具体实现方法:

#include

using namespace std;

class vvPtr1 {

public:

int a;

int b;

virtual void print() {

cout << “This. ok” << endl;

}//没有加virtual所以类的大小比属性与方法都相同的vvptr1小了4,指针的大小就是4;

virtual void print1() {//再增加一组virtual声明的函数,类的大小不再改变,

//更加有力的支持了vptr指针指向虚函数表

cout << “this 1” << endl;//然后完成多态,并不是对函数本身做了什么手脚

}

};

class vvPtr2 {

public:

int a1;

int c1;

void print() {

cout << “This. big ok” << endl;

}

void print1() {

cout << “this big 1” << endl;

}

};

int main_05() {

cout << “vvPrt1:” <<sizeof(vvPtr1)<<“vvPtr2:”<<sizeof(vvPtr2)<< endl;

return 0;

}

③子类的vptr指针分步初始化:

初始化子类对象时,首先构造基类的属性与方法,初始化子类对象时在基类

中调用能产生多态的函数时会产生调用基类的函数效果;也就是在初始化

对象期间并不产生多态,原因就是子类的vptr指针分步初始化,子类对象构

造完毕,指针初始化完成

初始化完基类属性,再初始化子类的属性,此时再调用多态函数会产生子类的函数效果

④子类与父类的步长问题;

当子类相比父类没有增加新的属性时,两种类的指针步长相同;

否则不相同,并且是子类的步长要大于父类的步长;

如果子类父类指针步长不同当定义一个对象数组时,用父类指针移动对象会出现问题;

这两个问题的实现方法如下:

#include

using namespace std;

class testparent {

public:

testparent() {

// print();

}

virtual void print() {

cout << “我是爸爸” << endl;

}

};

class testchild :public testparent{

public:

int a;

testchild() {

// print();

}

virtual void print() {

cout << “我是儿子” << endl;

}

};

int main_06() {

testchild pp;//构造时输出我是爸爸,我是儿子;

//所以在构造自己的基类属性时调用了基类的print在构造自己属性时调用了自己的print;

testchild test[3];//构造完后,子类的vptr指针指向自己的虚函数表;

testparent* p;

testchild* q;

p = test;

q = test;

p->print();

q->print();

p++;//如果子类没有计入新的属性,则步长相同,不会有什么问题;

q++;//如果子类中加入新的属性,再进行指针的位移,会出错,

p->print();//错的原因是基类指针位移的长度达不到子类下一对象的开始

q->print();

return 0;

}

五、纯虚函数与抽象类

============================================================================

1.定义纯虚函数语法(定义在类内):


virtual 返回类型 函数名(参数列表)=0;

有纯虚函数定义的类叫抽象类,并且抽象类不可以定义对象;

如果子类不将继承来的纯虚函数实例化;那么子类也将是抽象类;

抽象类中的函数可以作为接口使用,可以将多继承

中的基类变成抽象类将其内部的纯虚函数作为接口使用

2.纯虚函数与多继承:


多继承容易产生二义性,给代码维护带来灾难性的影响,

有纯虚函数类就被归为抽象类,该类不可以拿去定义对象;

而产生二义性就是因为子类不知道怎样调用父类里面的数据成员;

抽象类不定义对象,也就不用设置数据成员所以

将基类设置成抽象类避免了二义性的产生;

在抽象类中设置函数接口有利于后来写的类对抽象类函数进行实例化并投入使用实现相应的功能;

但这个不叫多态;

抽象类的使用场景:

#include

using namespace std;

class J1 {

public:

virtual int add(int a, int b) = 0;

virtual void print()=0;

};

class J2 {

public:

virtual int mutily(int a, int b) = 0;

virtual void print() = 0;

};

class child1:public J1,public J2 {

public:

virtual int add(int a, int b) {

return a + b;

}

virtual int mutily(int a, int b) {

一、Python所有方向的学习路线

Python所有方向路线就是把Python常用的技术点做整理,形成各个领域的知识点汇总,它的用处就在于,你可以按照上面的知识点去找对应的学习资源,保证自己学得较为全面。

二、学习软件

工欲善其事必先利其器。学习Python常用的开发软件都在这里了,给大家节省了很多时间。

三、入门学习视频

我们在看视频学习的时候,不能光动眼动脑不动手,比较科学的学习方法是在理解之后运用它们,这时候练手项目就很适合了。

网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。

需要这份系统化学习资料的朋友,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

  • 8
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值