好的面试官不会要求你用自己不懂的语言来编写代码。一般来说,如果面试官要求你用C++写代码,那么,应该是你在简历上提及了C++。要是没能记住所有API,也不用担心,大部分面试官(虽不是全部)并不会那么在意这一点。不过,我们仍建议你学会基本的C++语法,这样才能轻松应对这些问题。
类和继承
虽然C++的类与其他语言的类有些特征相似,不过,还是有必要回顾一下相关部分语法。
下面的代码演示了怎样利用继承实现一个基本的类。
在C++中,所有数据成员和方法均默认为私有(private),可用关键字public修改其属性。
构造函数和析构函数
对象创建时,会自动调用类的构造函数。如果没有定义构造函数,编译器会自动生成一个默认构造函数(DefaultConstructor)。另外,我们也可以定义自己的构造函数。
Person(inta){
id=a;}
这个类的数据成员也可以这样初始化:1Person(inta):id(a){2……3}
在真正的对象创建之前,且在构造函数余下部分代码调用前,数据成员id就会被赋值。在常量数据成员赋值时(只能赋一次值),这种写法特别适用。
析构函数会在对象删除时执行清理工作。对象销毁时,会自动调用析构函数。我们不会显式调用析构函数,因此它不能带参数。
~Person(){
deleteobj;//释放之前这个类里分配的内存}
虚函数
在前面的例子中,我们将p定义为Student类型指针变量:
Student*p=newStudent();
p-aboutMe();
像下面这样,把p定义为Person*又会怎么样?
这么改的话,执行时会打印“Iamaperson”。这是因为函数aboutMe是在编译期决定的,也即所谓的静态绑定(staticbinding)机制。
若要确保调用的是Student的aboutMe函数实现,可以将Person类的aboutMe定义为virtual:
当我们无法(或不想)实现父类的某个方法时,虚函数也能派上用场。例如,设想一下,我们想让Student和Teacher继承自Person,以便实现一个共同的方法,如addCourse(strings)。不过,对Person调用addCourse方法没有多大意义,因为要看对象到底是Student还是Teacher,才能确定该调用哪个方法的具体实现。
在这种情况下,我们可能想将Person类的addCourse定义为虚函数,至于函数实现则留给子类。
注意,将addCourse定义为纯虚函数,Person就成了一个抽象类,不能实例化。
虚析构函数
有了虚函数,很自然地就会出现虚析构函数的概念。假设我们想要实现Person和Student的析构函数。不假思索的话,可能会写出类似如下的代码:
跟之前的例子一样,由于指针p指向Person,对象销毁时自然会调用Person类的析构函数。这样就会有问题,因为Student对象的内存可能得不到释放。
要解决这个问题,只需将Person的析构函数定义为虚析构函数。
编译执行上面的代码,打印输出如下:
Deletingastudent.Deletingaperson.
默认值
如下所示,函数可以指定默认值。注意,所有默认参数必须放在函数声明的右边,因为没有其他途径来指定参数是怎么排列的。
操作符重载
有了操作符重载(operatoroverloading),原本不支持+等操作符的对象,就可以用上这些操作符。举个例子,要想把两个书架(BookShelf)并作一个,我们可以这样重载+操作符:
BookShelfBookShelf::operator+(BookShelfother){...}
指针和引用
指针存放有变量的地址,可直接作用于变量的所有操作,都可以作用在指针上,比如访问和修改变量。
两个指针可以彼此相等,修改其中一个指针指向的值,另一个指针指向的值也会随之改变。实际上,这两个指针指向同一地址。
注意,指针的大小随计算机的体系结构不同而不同:在32位机器上为32位,在64位机器上为64位。请谨记这一点区别,面试官常常会要求求职者准确地回答,某个数据结构到底要占用多少空间。
引用
引用是既有对象的另一个名字(别名),引用本身并不占用内存。例如:
在上面第2行代码中,b是a的引用;修改b,a也随之改变。
创建引用时,必须指定引用指向的内存位置。当然,也可以创建一个独立的引用,如下所示:
/*分配内存,储存12,
*声明指向这块内存的引用b*/
intb=12;
跟指针不同,引用不能为空,也不能重新赋值,指向另一块内存。
指针算术运算
我们经常会看到开发人员对指针执行加法操作,示例如下:
执行p++会跳过sizeof(int)个字节,因此上面的代码会输出1。如果p换作其他类型,p++就会跳过一定数目(等于该数据结构的大小)的字节。
模板
模板是一种代码重用方式,不同的数据类型可以套用同一个类的代码。比如说,我们可能有列表类的数据结构,希望可以放进不同类型的数据。下面的代码通过ShiftedList类实现这一需求。
template
classShiftedList{
T*array;
intoffset,size;
public:
ShiftedList(intsz):offset(0),size(sz){
array=new
T[size];
}
~ShiftedList(){
delete[]array;1
}
voidshiftBy(intn){
offset=(offset+n)%size;
}
TgetAt(inti){
returnarray[convertIndex(i)];
}
void
setAt(Titem,inti){
array[convertIndex(i)]=item;
}
private:
intconvertIndex(inti){
intindex=(i-offset)%size;
while(index0)index+=size;
returnindex;}
};
intmain(){
intsize=4;
ShiftedList*list=new
ShiftedList(size);
for(inti=0;isize;i++){
list-
setAt(i,i);
}
coutlist-getAt(0)endl;
cout
list-getAt(1)endl;
list-shiftBy(1);
coutlist-
getAt(0)endl;
coutlist-getAt(1)endl;
delete
list;
}