同学C++软件工程师的电话技术面试题:
(1)做了哪些项目;
(2)C++的特性;(封装、继承、多态)
(3)重载与重写的区别;
(4)之前有没有实习的经历。
(1)做了哪些项目;
基于ARM板的QT聊天室系统。
网络云盘。
还是要自己去熟悉,去完成这两个项目。————————(未完待续)
(2)C++的特性:封装,继承,多态;
A、数据封装,将数据和函数等集合在一个单元中,这个单元我们称之为类。
B、类的继承,主要实现重用代码。
继承是可以传递的。若C继承B,B又继承A,等于C既继承了B中的成员也继承了A中的成员。
#include<iostream>
using namespace std;
//熟悉继承的例子
class A
{//基类A
private:
int baseData;//基类A的私有成员
public:
//A(int x=0):baseData(x){}等价于A(int x=0){baseData=x;}
A(int x=0);//基类A的有参构造函数
void showA();//基类A的成员函数
};
A::A(int x)
{
baseData=x;
}
void A::showA()
{
cout<<"baseData="<<baseData<<"\t";
}
class B:public A
{//派生类B;B继承基类A
private:
int derivedData;//派生类的私有成员
public:
B(int x=0,int y=0);//派生类B的有参构造函数
void showB();//派生类B的成员函数
};
B::B(int x,int y):A(x)
{
derivedData=y;
}
void B::showB()
{
showA();//代码重用
cout<<"deriverData="<<derivedData<<endl;
}
int main()
{
A A(1);
B B(2,3);
cout<<"A.showA():\t";//输出结果是:1
A.showA();
cout<<endl;
cout<<"B.showB():\t";//输出结果:2 3
B.showB();
return 0;
}
C、函数多态,一个接口,多种方法。
- A、多态的精炼概括:
在基类的成员函数前面加上virtual关键字,然后在派生类中重写该函数,运行时会根据对象的实际类型来调用相应的函数。如果对象类型是派生类,就调用派生类的成员函数;如果对象类型是基类,就调用基类的函数。
- B、多态的分类:
编译时多态:是静态多态,指的是在编译时,其引用对象就可以确定。通过重载函数和运算符重载实现。(重载函数指的是相同函数名,不同的参数列表。所以创建对象时,根据其构造函数的参数列表就可以知道其引用对象。故编译时就知道引用对象了。)
运行时多态:是动态多态,指的是只有在运行的时候,其引用的对象才能够确定。通过虚函数和继承来实现。(虚函数,子类可以根据自己的需要,重写虚函数。)
- C、实现多态的主要方式:
实现多态的方法:虚函数,抽象类,覆盖(重写),模板。(重载与多态无关)
- D、多态的特点
(1)继承时多态存在的基础和前提,没有继承就没有多态。
(1)用virtual关键字声明的函数叫做虚函数。虚函数肯定是类的成员函数。
(2)同一个操作可以作用于不同的对象,产生不同的执行结果。(各个子类重写父类的方法,重写虚函数)
(3)多态用虚函数类实现,结合动态绑定。
(4)纯虚函数是虚函数再加上=0。如virtual void eat()=0;。
(4)抽象类是指包含至少一个纯虚函数的类。如基类A中包含成员函数virtual void eat()=0;那么这个基类A就叫做抽象类。必须在A的子类中实现这个纯虚函数。即先有名称,没有内容;在派生类中实现内容。
- E、多态的典例:
首先定义一个动物类,有抽象方法eat();
再定义一个家禽类,继承动物类;
再定义一个小鸡类,继承家禽类,实现抽象方法eat();
再定义一个熊猫类,继承动物类,实现抽象方法eat();
小鸡和熊猫就是多态。
#include<iostream>
#include<string>//必须有
using namespace std;
//熟悉多态的例子
class Animal
{
private:
string name;
public:
Animal(string n="动物")
{
name=n;
}
virtual void eat()
{
cout<<"喜欢吃的食物各不相同"<<endl;
}
string getName()
{
return name;
}
};
class Poultry:public Animal//默认是friendly,就不能访问Animal的getName成员函数
{
public:
Poultry(string n="家禽"):Animal(n){}
};
class Chicken:public Poultry//默认是friendly,就不能访问Poultry的getName成员函数
{
public:
Chicken(string n="小鸡"):Poultry(n){}
virtual void eat()
{
cout<<"爱吃的食物是谷物。"<<endl;
}
};
class Panda:public Animal//默认是friendly,就不能访问Poultry的getName成员函数
{
public:
Panda(string n="熊猫"):Animal(n){}
virtual void eat()
{
cout<<"爱吃的食物是竹子"<<endl;
}
};
void show(Animal *Ptr)
{
cout<<Ptr->getName()<<"——";
Ptr->eat();
}
int main()
{
//Chicken chicken("小鸡");
//cout<<chicken.getName()<<"——";
//chicken.eat();
//Panda panda("熊猫");
//cout<<panda.getName()<<"——";
//panda.eat();
int i;
Animal *Ptr[4];
Ptr[0]=new Chicken("小鸡");
Ptr[1]=new Panda("熊猫");
Ptr[2]=new Poultry("家禽");
Ptr[3]=new Animal("动物");
for(i=0;i<4;i++)
{
show(Ptr[i]);
}
for(i=0;i<4;i++)
{
delete Ptr[i];//释放动态存储空间
}
return 0;
}
(3)什么叫重载和重写,他们之间的区别时什么?
重载是参数列表有所不同,包括参数个数,参数类型;其他的返回值可以相同可以不同;
重写满足:参数列表和返回值都要严格与被重写函数相同。
(4)之前有没有什么实习的经验。