寒武纪C++日常实习生面经(其他人面试题)
1.C++继承方式?
答:public,protected,private三种继承方式和虚继承一共四种。
派生类可以继承定义在基类中的成员,但是派生类的成员函数不一定有权访问从基类继承而来的成员。
派生类将除了基类的构造函数和析构函数以外的所有成员都继承下来了。
虚继承:
虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承(菱形继承)而出现的。如:类D继承自类B1、B2,而类B1、B2都继承自类A,因此在类D中两次出现类A中的变量和函数。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。实现的代码如下:
class A
class B1:public virtual A;
class B2:public virtual A;
class D:public B1,public B2;
虚拟继承在一般的应用中很少用到,所以也往往被忽视,这也主要是因为在C++中,多重继承是不推荐的,也并不常用,而一旦离开了多重继承,虚拟继承就完全失去了存在的必要因为这样只会降低效率和占用更多的空间。
2.B C虚继承A,D public继承 B C ,有A *a = new D,a->fun(),fun是虚函数,并且B C都重写了,怎么保证a调用的是B重写的虚函数。
// B C虚继承A,D public继承 B C ,有A *a = new D,a->fun(),fun是虚函数,
// 并且B C都重写了,怎么保证a调用的是B重写的虚函数
#include <iostream>
using namespace std;
class A
{
public:
virtual void fun() { cout << "A::fun()." << endl; }
};
class B :public virtual A
{
public:
void fun() { cout << "B::fun()." << endl; }
};
class C :public virtual A
{
public:
void fun() { cout << "C::fun()." << endl; }
};
class D :public B, public C
{
public:
void fun() { cout << "D::fun()." << endl; }
};
int main()
{
A* a = new D;
A* b = new B;
a = b;
a->fun();
return 0;
}
// 输出:B::fun().
3.说说多态 静态+动态
![](https://img2018.cnblogs.com/blog/1425284/201906/1425284-20190628143441464-411891984.png)
静态多态(静态联编)
静态多态也称为静态绑定或早绑。编译器在编译期间完成的, 编译器根据函数实参的类型(可能会进行隐式类型转换) , 可推断出要调用那个函数, 如果有对应的函数就调用该函数, 否则出现编译错误。
int Add(int left,int right)
{
return left + right;
}
float Add(float left, float right)
{
return left + right;
}
int main()
{
cout<<Add(1,2)<<endl; //调用int Add()函数
cout<<Add(1.34f,3.21f)<<endl; //调float Add()函数
return 0;
}
动态多态(动态联编)
动态绑定: 在程序执行期间(非编译期) 判断所引 用对象的实际类型, 根据其实际类型调用相应的方法。使用virtual关键字修饰类的成员 函数时, 指明该函数为虚函数, 派生类需要重新实现, 编译器将实现动态绑定。
额外问题:为什么有两种类型的联编以及为什么默认为静态联编?
答:如果动态联编让您能够重新定义类方法,而静态联编在这方面很差,为何不摒弃静态联编呢?原因有两个----效率和概念模型。
1 首先来看效率。为使程序能够在运行阶段进行决策,必须采取一些方法来跟踪基类指针或引用指向的对象类型,这增加了额外的处理开销,例如,如果类不会用作基类,则不需要动态联编。同样,如果派生类不重新定义基类的任何方法,也不需要使用动态联编。在这些情况下,使用静态联编更合理,效率也更高。由于静态联编的效率更高,因此被设置为C++的默认选择。Strousstrup说,C++的指导原则之一是,不要为不使用的特性付出代价(内存或处理时间)。仅当程序设计确实需要虚函数时,才使用它们。
2 接下来看概念模型.在设计类时,可能包含一些不在派生类重新定义的成员函数.不将访函数设置为虚函数有两方面好处:首先效率高;其次,指出不要重新定义该函数.这表明,仅将那些预期将被重新定义的方法声明为虚拟的。
4.说说引用,什么时候用引用好,什么时候用指针好?
使用引用参数的主要原因有两个:
- 程序员能修改调用函数中的数据对象
- 通过传递引用而不是整个数据–对象,可以提高程序的运行速度
一般的原则:
对于使用引用的值而不做修改的函数:
- 如果数据对象很小,如内置数据类型或者小型结构,则按照值传递
- 如果数据对象是数组,则使用指针(唯一的选择),并且指针声明为指向const的指针
- 如果数据对象是较大的结构,则使用const指针或者引用,已提高程序的效率。这样可以节省结构所需的时间和空间
- 如果数据对象是类对象,则使用const引用(传递类对象参数的标准方式是按照引用传递)
对于修改函数中数据的函数:
- 如果数据是内置数据类型,则使用指针
- 如果数据对象是数组,则只能使用指针
- 如果数据对象是结构,则使用引用或者指针
- 如果数据是类对象,则使用引用