您的位置:首页 > 职场人生

面试宝典9,10,11--STL模板与容器;面向对象;继承与接口

2012-08-24 09:20 465 查看
1.删除array中所有的6(迭代器失效问题)

#include <iostream>
#include <vector>
using namespace std;

void print(vector<int>);

int main()
{
vector<int> array;
array.push_back(1);
array.push_back(6);
array.push_back(6);
array.push_back(3);

vector<int>::iterator itor;

for(itor=array.begin();itor!=array.end();itor++)
{
if(*itor == 6)
{
// version 1:
array.erase(itor);
itor--;

// version 2:
//itor=array.erase(itor);
//itor--;
}
}

print(array);

return 0;
}

void print(vector<int> v)
{
cout<<"\n vector size is: "<<v.size()<<endl;
for(vector<int>::iterator i=v.begin();i!=v.end();i++)
cout<<*i<<endl;
}

2.指出下面程序的错误,如果把静态成员数据设为私有,该如何访问?

#include <iostream>

using namespace std;

class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}
static int HowManyCats;    //静态成员变量
private:
int itsAge;
};

//int Cat::HowManyCats=0;   //需给静态成员变量赋初值

int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
CatHouse[i]=new Cat(i);
for(i=0;i<MaxCats;i++)
{
cout<<"There are ";
cout<<Cat::HowManyCats;
cout<<" cats left!\n";
cout<<"Deleting the one which is ";
cout<<CatHouse[i]->GetAge();
cout<<" years old\n";
delete CatHouse[i];
CatHouse[i]=0;
}

return 0;
}

答案:该程序错在设定了静态成员变量,却没有给静态成员变量赋初值。可以在源程序的基础上添加赋值语句:int Cat::HowManyCats=0;程序结果为:



如果把静态成员数据设为私有,则1,可以通过公有成员函数访问(前提是访问时需要通过构造好的对象来使用公有成员函数)。2,通过公有静态成员函数访问(可以直接通过类使用公有静态成员函数)。方法一如下:

#include <iostream>

using namespace std;

class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}

int GetHowMany()
{
//return HowManyCats;
cout<<"There are "<<HowManyCats<<" Cats alive!\n";
}
private:
int itsAge;
static int HowManyCats;

};

int Cat::HowManyCats=0;

int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
{
CatHouse[i]=new Cat(i);
CatHouse[i]->GetHowMany();
}
for(i=0;i<MaxCats;i++)
{
delete CatHouse[i];
CatHouse[i]->GetHowMany();
}
return 0;
}

方法二中增添了函数count()调用公有静态成员函数GetHowMany(),方法二如下:

#include <iostream>

using namespace std;

class Cat
{
public:
Cat(int age):itsAge(age)
{
HowManyCats++;
}
virtual ~Cat()
{
HowManyCats--;
}
virtual int GetAge()
{
return itsAge;
}
virtual void SetAge(int age)
{
itsAge=age;
}

static int GetHowMany()  //
{
return HowManyCats;
}
private:
int itsAge;
static int HowManyCats;

};

int Cat::HowManyCats=0;

int count()
{
cout<<"There are "<<Cat::GetHowMany()<<" Cats alive!\n";
}

int main()
{
const int MaxCats=5;
int i;
Cat *CatHouse[MaxCats];
for(i=0;i<MaxCats;i++)
{
CatHouse[i]=new Cat(i);
count();
}
for(i=0;i<MaxCats;i++)
{
delete CatHouse[i];
count();
}
return 0;
}
得到的结果均为:



3.初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的。

4.这个类声明正确吗?为什么?

class A
{
const int Size=0;
};
答案:不正确。常量必须在构造函数的初始化列表里面初始化或者将其设置成static。
解析:可以参考C++成员变量初始化问题

正确的程序可以为:

class A

{   

  static const int Size=0;

};

或者为:

class A

{

  public:

     A():Size(0)

     {}

  private:

    const int Size;

};

5.析构函数可以是内联函数。

6.请看下面一段程序。

#include <iostream>
#include <string>

using namespace std;

class B
{
private:
int data;
public:
B()
{
cout<<"default constructor"<<endl;
}
~B()
{
cout<<"destructed"<<endl;
}
B(int i):data(i)
{
cout<<"constructed by parameter "<<data<<endl;
}
};

B Play(B b)
{
return b;
}

int main()
{
B temp=Play(5);

return 0;
}
问题:

(1)该程序输出的结果是什么?为什么会有这样的输出?

(2)B(int i):data(i),这种用法的专业术语叫什么?

(3)Play(5),形参类型是类,而5是个常量,这样写合法吗?为什么?

答案:

(1)输出的结果如下图所示:



constructed by parameter 5  //在Play(5)处,5通过隐含的类型转换调用了B::B(int i)

destructed   //Play(5)返回时,参数的析构函数被调用

destructed   //temp的析构函数调用:temp的构造函数调用的是编译器生成的拷贝构造函数,原来以为调用的是生成的赋值构造函数,结果查了下资料发现自己说错了,具体的解释见:拷贝构造函数与赋值构造函数,拷贝构造函数是在对象被创建时调用,而赋值构造函数只能被已经存在了的对象调用。

(2)带参数的构造函数,冒号后面是成员变量初始化列表(member initialization list)。

(3)合法。单个参数的构造函数如果不添加explicit关键字,会定义一个隐含的类型转换(从参数类型转换到自己的类类型);添加explicit关键字会消除这种隐含转换。

7.编写类String的构造函数、析构函数和赋值函数。

答案:

已知类String的原型为:

class String
{
public:
String(const char *str=NULL);             // 构造函数
String(const String &other);              // 拷贝构造函数
String& operator=(const String &other);   // 赋值构造函数
~String(void);                            // 析构函数
private:
char *m_data;                            // 用于保存字符串
};
编写String的上述四个函数:

String::String(const char *str=NULL)
{
if(str==NULL)
{
m_data=new char[1];
m_data='\0';
}
else
{
int length=strlen(str);
m_data=new char[length+1];
strcpy(m_data, str);
}
}

String::String(const String &other)
{
int length=strlen(other.m_data);
m_data=new char[length+1];
strcpy(m_data, other.m_data);
}

Sting& String::operator=(const String &other)
{
if(this==&other)
return *this;
else
{
delete [] m_data;
int length=strlen(other.m_data);
m_data=new char[length+1];
strcpy(m_data, other.m_data);
return *this;
}
}

String::~String()
{
delete [] m_data;
}


8.重载是指编写一个与已有函数同名但是参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)的函数。

9.若类中包含了需要深拷贝的字符指针,则需要编写拷贝构造函数与赋值构造函数。

10.以下代码的输出结果是什么?

#include <iostream>

using namespace std;

class A
{
protected:
int m_data;
public:
A(int data=0)
{
m_data=data;
}
int GetData()
{
return doGetData();
}
virtual int doGetData()
{
return m_data;
}
};

class B:public A
{
protected:
int m_data;
public:
B(int data=1)
{
m_data=data;
}
int doGetData()
{
return m_data;
}
};

class C:public B
{
protected:
int m_data;
public:
C(int data=2)
{
m_data=data;
}
};

int main()
{
C c(10);

cout<<c.GetData()<<endl;
cout<<c.A::GetData()<<endl;
cout<<c.B::GetData()<<endl;
cout<<c.C::GetData()<<endl;
cout<<c.doGetData()<<endl;
cout<<c.A::doGetData()<<endl;
cout<<c.B::doGetData()<<endl;
cout<<c.C::doGetData()<<endl;

system("PAUSE");
return 0;
}

答案:



解析:构造函数从最初始的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。就近调用原则:如果父辈存在相关接口则优先调用父辈接口,如果父辈也不存在相关接口则调用祖父辈接口。
其中c.A::doGetData()用到了覆盖虚函数机制,直接调用A中的doGetData()。

11.以下代码的输出结果是是什么?

#include <iostream>

using namespace std;

class A
{
public:
void virtual f()
{
cout<<"A"<<endl;
}
};

class B:public A
{
public:
void virtual f()
{
cout<<"B"<<endl;
}
};

int main()
{
A *pa= new A();
pa->f();
B *pb=(B*)pa;
pb->f();

delete pa, pb;
pa= new B();
pa->f();
pb=(B*)pa;
pb->f();
}
答案:



12.考虑A到J语句在编译时可能出现的情况,判断出各个语句的正确性。

#include <iostream>

class Parent
{
public:
Parent(int var=-1)
{
m_nPub=var;
m_nPtd=var;
m_nPrt=var;
}
public:
int m_nPub;
protected:
int m_nPtd;
private:
int m_nPrt;
};

class Child1:public Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;}     //A
};

class Child2:protected Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;}     //B
};

class Child3:private Parent
{
public:
int GetPub(){return m_nPub;}
int GetPtd(){return m_nPtd;}
int GetPrt(){return m_nPrt;}     //C
};

int main()
{
Child1 cd1;
Child2 cd2;
Child3 cd3;

int nVar=0;

//public inherited
cd1.m_nPub=nVar;
//D
cd1.m_nPtd=nVar;
//E
nVar=cd1.GetPtd();
//F

//protected inherited
cd2.m_nPub=nVar;
//G
nVar=cd2.GetPtd();
//H

//private inherited
cd3.m_nPub=nVar;
//I
nVar=cd3.GetPtd();
//J

return 0;
}
答案:

A,B,C,E,G,I是“ERROR”。

D,F,H,J是“RIGHT”。

解析:参考:C++中private,public,protected的访问

13.下面程序的结果是什么?

#include <iostream>

using namespace std;

class A
{
char k[3];
public:
virtual void aa(){};
};

class B:public virtual A
{
char j[3];
public:
virtual void bb(){};
};

class C:public virtual B
{
char i[3];
public:
virtual void cc(){};
};

int main()
{
cout<<"sizeof(A): "<<sizeof(A)<<endl;
cout<<"sizeof(B): "<<sizeof(B)<<endl;
cout<<"sizeof(C): "<<sizeof(C)<<endl;

return 0;
}
答案:程序运行结果如下:



解析:涉及到C++中虚继承的问题。

虚拟继承是多重继承中特有的概念。虚拟基类是为解决多重继承而出现的。如下图所示。



类D继承自类B1、B2,而类B1、B2都继承自类A,因此出现如右图所示的局面(非虚基类)。为了节省内存空间,可以将B1、B2对A的继承定义为虚拟继承,而A就成了虚拟基类。最后形成如左图所示的情况。

实现的代码如下:

class A;   //忽略C1和C2

class B1:public virtual A;

class B2:public virtual A;
class D:public B1,public B2;

以sizeof(B)为例,sizeof(B)= char j[3]所占大小4 + 虚指针vfptr_B所占大小4 + sizeof(A)所占大小8 = 16

若不采用虚继承的方式而是直接继承,结果就不会产生偏移,结果为:



14.如果不指定public,C++默认的是私有继承。

15.Find the defects in each of the following programs, and explain why it is incorrect.

class base
{
private:
int i;
public:
base(int x){i=x;}
};

class derived:public base
{
private:
int i;
public:
derived(int x, int y){i=x;}

void printTotal()
{
int total=i+base::i;
}
};
答案:1,派生类构造函数没有初始化基类成员变量值。2,派生类成员函数访问基类的私有成员。

修改如下:1,在派生类derived()构造函数中调用基类构造函数base()初始化基类成员变量i。2,讲派生类中成员i的访问标示符由private改为protected。

class base
{
protected:
int i;
public:
base(int x){i=x;}
};

class derived:public base
{
private:
int i;
public:
derived(int x, int y):base(x)
{
y=i;
}

void printTotal()
{
int total=i+base::i;
}
};

16.下面的程序有何错误?

#include <iostream>

using namespace std;

class Shape
{
public:
Shape(){}
~Shape(){}
virtual void Draw()=0;
};

int main()
{
Shape s1;
}
答案:因为Shape类中的Draw函数是一个纯虚函数,所以Shape为一个抽象类,故Shape不能实例化为一个对象。解决方法是将Draw函数改为一般的虚函数。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  面试 iterator vector