面试宝典9,10,11--STL模板与容器;面向对象;继承与接口
2012-08-24 09:20
465 查看
1.删除array中所有的6(迭代器失效问题)
2.指出下面程序的错误,如果把静态成员数据设为私有,该如何访问?
答案:该程序错在设定了静态成员变量,却没有给静态成员变量赋初值。可以在源程序的基础上添加赋值语句:int Cat::HowManyCats=0;程序结果为:
如果把静态成员数据设为私有,则1,可以通过公有成员函数访问(前提是访问时需要通过构造好的对象来使用公有成员函数)。2,通过公有静态成员函数访问(可以直接通过类使用公有静态成员函数)。方法一如下:
方法二中增添了函数count()调用公有静态成员函数GetHowMany(),方法二如下:
3.初始化列表的初始化变量顺序是根据成员变量的声明顺序来执行的。
4.这个类声明正确吗?为什么?
解析:可以参考C++成员变量初始化问题。
正确的程序可以为:
class A
{
static const int Size=0;
};
或者为:
class A
{
public:
A():Size(0)
{}
private:
const int Size;
};
5.析构函数可以是内联函数。
6.请看下面一段程序。
(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的原型为:
8.重载是指编写一个与已有函数同名但是参数表不同(或许参数个数不同,或许参数类型不同,或许两者都不同)的函数。
9.若类中包含了需要深拷贝的字符指针,则需要编写拷贝构造函数与赋值构造函数。
10.以下代码的输出结果是什么?
答案:
解析:构造函数从最初始的基类开始构造,各个类的同名变量没有形成覆盖,都是单独的变量。就近调用原则:如果父辈存在相关接口则优先调用父辈接口,如果父辈也不存在相关接口则调用祖父辈接口。
其中c.A::doGetData()用到了覆盖虚函数机制,直接调用A中的doGetData()。
11.以下代码的输出结果是是什么?
12.考虑A到J语句在编译时可能出现的情况,判断出各个语句的正确性。
A,B,C,E,G,I是“ERROR”。
D,F,H,J是“RIGHT”。
解析:参考:C++中private,public,protected的访问
13.下面程序的结果是什么?
解析:涉及到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.
修改如下:1,在派生类derived()构造函数中调用基类构造函数base()初始化基类成员变量i。2,讲派生类中成员i的访问标示符由private改为protected。
16.下面的程序有何错误?
#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函数改为一般的虚函数。
相关文章推荐
- 黑马程序员——java第七天:面向对象(继承、子父类之变量、final、抽象、模板方法、接口)
- C++面试宝典之STL向量容器
- 11) 为STL容器和数组提供统一的接口DataSet [原创,泛型编程,自由下载转载,需注明出处]
- C++面试宝典之STL向量容器
- StringTemplate.Net 学习笔记(10):模板组继承及模板组接口
- C++面试笔记--STL模板与容器
- 面向对象—10—继承、抽象类、模板设计模式
- java基础(六)——面向对象_继承、抽象类、接口
- 黑马程序员_java的面向对象(对第七课继承..抽象类..接口及fianl应用总结)
- Jser 设计模式系列之面向对象 - 接口封装与继承
- 黑马程序员---Java基础---面向对象:继承、抽象类、接口
- 【C/C++学院】(10)重载与重写/多态的深入/多继承接口
- 面向对象:接口继承还是类继承?
- c++的STL模板库中3种容器类:vector,list,deque的比较
- 面向对象 继承 接口
- C#编程入门10_面向对象之继承
- C++ STL模板与容器 知识 初学 小结 ( 一 )
- 不要在公共接口中传递STL容器
- 11/7/8 STL 映射容器 map< K , T > 学习笔记
- 12月30日 面向对象03(继承 抽象类 接口)