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

来源:互联网 发布:什么软件升级显卡 编辑:程序博客网 时间:2024/05/17 23:30

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函数改为一般的虚函数。


原创粉丝点击