写在最后
最后我想说:对于程序员来说,要学习的知识内容、技术有太多太多,要想不被环境淘汰就只有不断提升自己,从来都是我们去适应环境,而不是环境来适应我们!
这里附上上述的技术体系图相关的几十套腾讯、头条、阿里、美团等公司2021年的面试题,把技术点整理成了视频和PDF(实际上比预期多花了不少精力),包含知识脉络 + 诸多细节,由于篇幅有限,这里以图片的形式给大家展示一部分。
相信它会给大家带来很多收获:
当程序员容易,当一个优秀的程序员是需要不断学习的,从初级程序员到高级程序员,从初级架构师到资深架构师,或者走向管理,从技术经理到技术总监,每个阶段都需要掌握不同的能力。早早确定自己的职业方向,才能在工作和能力提升中甩开同龄人。
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
2. 如何实现多继承?
C++中,我们可以在派生列表中包含多个基类:
class Sub : public Base{
...
}
class SubA : public Base1, public Base2{
...
}
关于多继承的几点说明:
- 每个基类均包含一个可选的访问说明符;
- 派生类列表只能包含已经被定义过的类;并且这些类不能是final的;
- C++对于派生类能继承的积累个数没有特殊规定,但是派生类列表中同一个基类只能出现一次。比如:可以
Sub:public Base1,public Base2,public Base3 ....
,但是不能Sub:public Base1,Base1
.
3. 多继承中从每个基类中继承的状态
在多继承中,子类的对象包含每个基类的子对象,比如Sub继承Base1,Base2,Base1又继承自Base,那么Sub对象的结构如下图:
构造一个派生类的对象将同时构造并初始化它的所有基类子对象,并且多重继承的派生类的构造函数值也只能初始化它的直接子类。
子类的构造方法初始值列表将实参分别传递给每个直接父类。父类的构造顺序与派生列表中基类的出现顺序保持一致,而与派生类构造函数初始值列表中基类的顺序无关。怎么理解这句话呢?就是构造顺序与class Sub : public Base1, public Base2
这个顺序有关,而与Sub::Sub(std::string name):Base1(name),Base2(){}
没有关系。
在C++11新标准中,允许派生类从它的一个或几个基类中继承构造函数,但是如果从多个基类中集成了相同的构造函数,程序就会出错。
比如Base1,Base2 都有以const st::string&
参数的构造函数,那么Sub同时继承Base1,Base2就会出错,这个时候我们必须专门为Sub定义自己的构造函数Sub:Sub(const std::string &s):Base1(s),Base2(s)
。
4. 多重继承中的类型转换
子类继承多个父类的情况下,我们可以令某个可访问基类的指针或引用直接指向一个子类对象。比如:
Base1 *base1 = new Sub();
Base2 *base2 = new Sub();
Base base = new Sub();
编译器不会在子类像基类的几种转换中进行比较和选择,因为它认为转换成哪个父类都行。但是这样会带来二义性,比如重载方法时:
void action(const Base1&);
void action(const Base2&);
当我们给action传Sub对象时就会出问题,因为编译器不知道怎么转换了。
所以我们在重载方法时要注意这种类型转换可能引起的问题。
5. 多重继承中的资源查找
在Java中我们查找属性时先从子类找,找不到再找父类,C++也是类似,但是在多重继承的结构中可能会有些复杂。
因为在查找过程中,会在所有直接基类中同时进行,如果名字在多个基类中都被找到,则这个属性的名字就产生了二义性。
我们思考一个问题,在Java中,如果我们定义了两个接口A,B,它们都有void test()
这么一个方法,那么我们的Test类如果同时实现了A,B接口,具体的类该怎么实现呢?
在Java中确实比较简单,只需要实现一个test()方法就可以,但是在C++的多重继承中,父类不仅有方法还有属性,这种二义性该怎么解决呢?在C++中,对于一个派生类来说,从它的几个基类中分别继承名字相同的成员是完全合法的,只是需要在我们使用这些名字是加上前缀限定符明确指定它属于哪个基类(不调用不会出错,如果调用了还没有加前缀就会出错)。
比如上面说的test方法,我们的子类可以使用sub->Base1::text()
方法来调用。
还有一种更复杂的情况,就是派生类继承的两个基类有函数名相同,但是参数列表不同的方法,这样查找是更容易出错。
**最佳实践:**为了避免二义性,除了我们在调用时加前缀,最好的办法是在派生类中为这个函数定义一个自己的版本,在函数内部来屏蔽这些二义性。比如:
int Sub::getMax() const
{
return std::max(Base1::getMax(), Base2::getMax());
}
6. 虚继承
我们在派生类列表中见过这么一种形式:
class Base1:public virtual Base{
...
}
结语
由于篇幅限制,文档的详解资料太全面,细节内容太多,所以只把部分知识点截图出来粗略的介绍,每个小节点里面都有更细化的内容!以下是目录截图:
由于整个文档比较全面,内容比较多,篇幅不允许,下面以截图方式展示 。
再附一部分Android架构面试视频讲解:
网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!
这份系统化学习资料的朋友,可以戳这里获取](https://bbs.csdn.net/topics/618156601)**
一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!