c++ 继承的面试概念以及基础知识题

本文详细解析了C++中派生类的构造过程,访问基类成员的方式,类型兼容规则,以及公有、保护和私有继承的区别。讨论了多继承中的二义性和解决方案,包括友元函数与虚基类。同时涵盖了派生类构造函数的执行顺序和继承与组合的对比。
摘要由CSDN通过智能技术生成

1.概念填空题 

1.1在C++中,三种派生方式的说明符号为  public(公有继承) 、  private(私有继承) 、  protected(保护继承)       不加说明,则默认的派生方式为  private(私有继承)     

1.2当公有派生时,基类的公有成员成为派生类的   公有成员        ;保护成员成为派生类的  保护成员         ;私有成员成为派生类的    不可访问对象        

当保护派生时,基类的公有成员成为派生类的  保护成员        ;保护成员成为派生类的  保护成员          ;私有成员成为派生类的  不可访问对象            

1.3 派生类的构造函数一般有3项工作要完成:首先 基类初始化        ,其次   成员对象初始化       ,最后   派生类的构造函数初始化          。 

1.4多继承时,多个基类中的同名的成员在派生类中由于标识符不唯一而出现 二义性 。在派生类中采用   作用域分辨符           或   虚基类           来消除该问题。  

2.简答题 

2.1 派生类如何实现对基类私有成员的访问? 

答:用友元函数,友元函数可以打破类的封装。

2.2什么是类型兼容规则?

答:在需要基类对象的任何地方,都可以使用公有派生类来代替基类。通过公有继承,派生类得到了基类中除构造函数,析构函数之外的所有成员。这样,公有派生类实际就具备了基类的所有功能,凡是基类能解决的问题,公有派生类都可以解决。 

2.3派生类的构造函数是怎样的执行顺序,析构函数的执行顺序是如何实现的?

答:Frist,调用基类构造函数,然后按照基类成员在类声明出现的顺序对这些成员进行初始化,然后,调用派生构造函数,析构函数的执行顺序与构造函数相反。虚基类的对象优先被构造。

 2.4继承与组合之间的区别与联系是什么?

答:继承是面向对象的三大基本特征之一,继承就是子类继承父类的特征和行为,使得子类对象具有父类的实例域和方法,或子类从父类继承方法,使得子类具有父类相同的行为,继承强调的是is-a的关系(多继承也有has——a关系),继承是代码复用的一种方式,在继承中,父类方法的内部实现细节对子类可见,是白盒式的方法复用。组合是通过对现有对象进行拼装即组合产生新的具有更复杂的功能,组合体现的是整体和部分,强调的是hasa的关系,而组合中,对象之间的内部细节不可见,是黑盒式复用。继承在编码过程中就要指定具体的父类,其关系在编译期就确定,和组合的关系一般在运行期时确定。 

2.5什么是虚基类?它有什么作用?含有虚基类的派生类的构造函数有什么要求,什么是最远派生类,建立一个含有虚基类的派生类的对象时,为什么由最远派生类的构造函数负责虚基类的初始化?

答:当在多余基础路径上有一个公共的基类,在这些路径的某几条汇合处,这个公共的基类就会产生多个实例,若只想保存这个基类的一个实例,可以将这个公共基类说明问派生类。含有虚基类的派生类构造函数,如果虚基类的构造函数是默认或者缺省构造函数那么后面的派生类则无需对虚基类的构造函数调用了,需要注意的是如果虚基类中没有默认构造函数,或者中间的派生类采用的不是默认构造函数或者有参数,那么在所有的派生类中都必须要有虚基类构造函数的说明。因为只有最远派生类对虚基类的构造函数使用有效,之后的都是无效的,而且构造函数只能被调用一次。  

3.选择题 

3.1下面对派生类的描述中,错误的是()。 

     A.一个派生类可以作为另外一个派生类的基类      B.派生类至少有一个基类 

     C.派生类的成员除了它自己的成员外,还包含了它的基类的成员      D.派生类中继承的基类成员的访问  权限到派生类中保持不变 

3.2下列对友元关系叙述正确的是(AD)。     

 A.不能继承                                                             B.是类与类的关系 

           C.是一个类的成员函数与另一个类的关系      D.提高程序的运行效率 

3.3当保护继承时,基类的(B)在派生类中成为保护成员,不能通过派生类的对象来直接访问。 

  1. 任何成员                          B.公有成员和保护成员       C.公有成员和私有成员                D.私有成员 

3.4设置虚基类的目的是(B)。 

A.简化程序                             B.消除二义性 

          C.提高运行效率                      D.减少目标代码 

3.5在公有派生情况下,有关派生类对象和基类对象的关系,不正确的叙述是( )。         

  1. 派生类的对象可以赋给基类的对象        

B.派生类的对象可以初始化基类的引用 

          C.派生类的对象可以直接访问基类中的成员 

          D.派生类的对象的地址可以赋给指向基类的指针 

3.6有如下类定义: 

class MyBASE{  

int k; 

public:   

void set(int n) {k=n;}  

int get( ) const {return k;} 

}; 

class MyDERIVED: protected MyBASE{ 

protected;  

int j; public:  

void set(int m,int n){MyBASE::set(m);j=n;}  

int get( ) const{return MyBASE::get( )+j;} 

}; 

则类MyDERIVED中保护成员个数是(B)。 

A.4                      B.3                      C.2                      D.1 

3.7程序如下: 

#include<iostream> 

using namespace std; 

class A { public:  A( ) {cout<<”A”;} }; 

class B {public:B( ) {cout<<”B”;} }; 

class C: public A{  B b; public:  C( ) {cout<<”C”;} }; 

int main( ) {C obj; return 0;} 

执行后的输出结果是(D)。       

  1. CBA                 B.BAC                            C.ACB                D.ABC 

3.8类O定义了私有函数F1。P和Q为O的派生类,定义为class P: protected  O{…}; class Q: public O{…}。( C)可以访问Fl。 

A. O的对象                B. P类内                      C. O类内           D. Q类内 

3.9有如下类定义: 

class XA{ int x;  public:   XA(int n) {x=n;}  }; 

class XB: public XA{  int y;   public: XB(int a,int b); }; 

在构造函数XB的下列定义中,正确的是(B)。        

  1. XB::XB(int a,int b):x(a),y(b){ }                               B.XB::XB(int a,int b):XA(a),y(b) { }         
  2. XB::XB(int a,int b):x(a),XB(b){ }                          D.XB::XB(int a,int b):XA(a),XB(b){ } 

3.10有如下程序:

#include<iostream> 

using namespace std; 

class Base{ 

private:  

void fun1( ) const {cout<<”fun1”;} 

protected:  

void fun2( ) const {cout<<”fun2”;} 

public:  

void fun3( ) const {cout<<”fun3”;}

}; 

class Derived : protected  Base{  

public:  

void fun4( ) const {cout<<”fun4”;}

}; 

int main(){

   Derived obj;  

obj.fun1( );  //①  

obj.fun2( );  //②  

obj.fun3( );  //③  

obj.fun4( );  //④ 

其中没有语法错误的语句是( D)。 

A.①                    B.②                    C.③                    D.④ 

  1. 写出程序运行结果 

l#include<iostream>

using namespace std; 

class B1{ 

public: 

B1(int i){ cout<<”constructing B1 “<<i<<endl; }  

~B1( ){ cout<<”destructing B1 “<<endl; } 

}; 

class B2 { 

public:  

B2( ){ cout<<”constructing B3 *”<<endl; }  

~B2( ){ cout<<”destructing B3”<<endl; } 

}; 

class C:public B2, virtual public B1 {  

  int j; 

public: 

  C(int a,int b,int c):B1(a),memerB2(), memberB1(b) ,j(c){} 

private:  

B1 memberB1;  B2 memberB2; 

}; 

int main( )

      C obj(1,2,3);   

运行:

constructing B1 1

constructing B3 *

constructing B1 2

constructing B3 *

destructing B3

destructing B1

destructing B3

destructing B1

4.2

#include<iostream>

using namespace std; 

class B{ 

public:  

void f1(){cout<<"B::f1"<<endl;} 

}; 

class D:public B{ 

public:  

void f1(){cout<<"D::f1"<<endl;} 

}; 

void f(B& rb){  rb.f1(); } 

int main( )

{  

D d;  

B b,&rb1=b,&rb2=d; 

f(rb1); 

f(rb2);  

return 0; 

}  

运行:

B::f1

B::f1

5.编程题 

5.1定义一个Point类,派生出Rectangle类和Circle类,计算各派生类对象的面积Area()。

 #include<iostream>
using namespace std;
const double PI=3.14159;
class Point {
public:
       Point(double x=0, double y=0) {X=x;Y=y;}
       void ShowPoint() {cout<<"("<< X<<","<<Y<<")"<<endl;}
private:
       double X,Y;
};
class Rectangle: public Point {
public:
       Rectangle(double w,double h,double x,double y):Point(x,y)
       {width=w,height=h;Area();}
       void Area() {area= width*height;}
       void ShowArea(){
              cout<<"Rectangle Area="<<area<<endl;
       }
private:
       double width,height,area;
};
class Circle: public Point {
public:
       Circle(double r,double x, double y):Point(x,y)
       {radius=r;Area();}
       void Area() {area= PI*radius*radius;}
       void ShowArea(){
              cout<<"Circle Area="<<area<<endl;
       }
private:
       double radius,area;
};
int main(){
       Rectangle r(10,8,0,0);
       Circle c(4,3,5);
       r.ShowArea();
       c.ShowArea();
       return 0;
}

5.2设计一个建筑物类Building,由它派生出教学楼Teach-Building和宿舍楼类Dorm-Building,前者包括教学楼编号、层数、教室数、总面积等基本信息,后者包括宿舍楼编号、层数、宿舍数、总面积和容纳学生总人数等基本信息。 

#include<iostream>
#include<cstring>
using namespace std;
enum AMPM{AM=1,PM};
class Building{
public:
       Building(char *);
       void ShowBuilding(){
              cout<<Name;
       }
protected:
       char Name[30];
};
Building::Building(char *name){
       strcpy(Name,name);
};
 
class Teach_Building: public Building {
public:
       Teach_Building(char *,int,int,int,int);
       void ShowTeach_Building(){
              Building::ShowBuilding();
              cout<<" No:"<<No;
              cout<<" Floors:"<<Floors;
              cout<<" ClassRooms:"<<ClassRooms;
              cout<<" Area:"<<Area<<endl;
       }
protected:
       int No,Floors,ClassRooms,Area;
};
Teach_Building::Teach_Building(char *name,int no,int fl,int cr,int ar):Building(name){
       No=no;Floors=fl;ClassRooms=cr;Area=ar;
}
class Dorm_Building:public Building {
public:
       Dorm_Building(char *,int,int,int,int,int);
       void ShowDorm_Building(){
              Building::ShowBuilding();
              cout<<" No:"<<No;
              cout<<" Floors:"<<Floors;
              cout<<" DormRooms:"<<DormRooms;
              cout<<" Area:"<<Area;
              cout<<" StudentNum:"<<StudentNum<<endl;
       }
protected:
       int No,Floors,DormRooms,Area,StudentNum;
};
Dorm_Building::   Dorm_Building(char *name,int no,int fl,int dr,int ar,int sn):Building(name){
       No=no;Floors=fl;DormRooms=dr;Area=ar;StudentNum=sn;
}
 
int main(){
       Teach_Building tb("
主教学楼",59,6,66,18000);
       Dorm_Building db("
北苑男生宿舍",41,5,75,3750,300);
       tb.ShowTeach_Building();
       db.ShowDorm_Building();
       return 0;
}

5.3利用NewClock类与Date类定义一个带日期的时钟类 ClockwithDate。对该类对象能进行增加减少秒数操作。 

#include<iostream>
using namespace std;
enum AMPM{AM=1,PM};
class Clock{
public:
       Clock(int=0, int=0, int s=0);
       void ShowTime(){
              cout<<Hour<<":"<<Minute<<":"<<Second;
       }
protected:
       int Hour,Minute,Second;
};
Clock::Clock(int h, int m, int s){
       Hour=h;Minute=m;Second=s;
};
 
class NewClock: public Clock {
public:
       NewClock(Clock c,AMPM ap):Clock(c){
              Ap=ap;
       }
       void ShowTime(){
              Clock::ShowTime();
              cout<<(Ap==AM ? " AM": " PM")<<endl;
       }
protected:
       AMPM Ap;
};
 
class Date{
protected:
       int Year,Month,Day;
       static const int days[];
       bool LeapYear();
       bool EndofMonth();
public:
       Date(int=1900,int=1,int =1);
       void Increment(int );
       void Decrement(int);
       void SetDate(int,int,int);
       void ShowDate();
};
 
const int Date::days[]={0,31,28,31,30,31,30,31,31,30,31,30,31};
 
Date::Date(int y,int m,int d){
       SetDate(y,m,d);
}
void Date::SetDate(int y,int m,int d){
       Year=(y>=1900 && y<=9999)?y:1900;
       Month=(m>=1 &&m<=12)?m:1;
       if(Month==2 && LeapYear())
              Day=(d>=1 && d<=29)?d:1;
       else
              Day=(d>=1 && d<=days[Month])?d:1;
}
 
bool Date::LeapYear(){
       return ((Year%400 == 0) || (Year%4==0 && Year%100!=0))? true:false;
}
bool Date::EndofMonth(){
       if(Month==2 && LeapYear())
              return Day==29;
       else
              return Day==days[Month];
}
void Date::Increment(int n){
       int i;
       for(i=1;i<=n;i++)
       if(EndofMonth() && Month==12){
              Year++;  Month=Day=1;
       }
       else if(EndofMonth()){
              Month++;Day=1;
       }
       else
              Day++;
}
void Date::Decrement(int n){
       int i;
       for(i=1;i<=n;i++)
       if(Day==1){
              if(Month==1){
                     Year--; Month=12; Day=31;
              }
              else if(Month==3){
                     Day=LeapYear()?29:28;Month=2;
              }
              else
                     Day=days[--Month];
       }
       else
              Day--;
}
 
void Date::ShowDate(){
       cout<<Year<<"-"<<Month <<"-"<<Day <<endl;
}
 
class ClockwithDate :public Date,public NewClock{
public:
       ClockwithDate(Date,Clock,AMPM);
       void IncrementSecond(int);
       void DecrementSecond(int);
       void ShowDateandTime(){
              Date::ShowDate();
              NewClock::ShowTime ();
       }
};
ClockwithDate::ClockwithDate(Date d,Clock c,AMPM ap):Date(d),NewClock(c,ap){}
void ClockwithDate::IncrementSecond(int n){
       int i;
       for(i=1;i<=n;i++){
              Second++;
              if(Second==60){
                     Second=0;
                     Minute++;
                     if(Minute==60){
                            Minute=0;
                            Hour++;
                            if(Hour==24){
                                   Hour=0;
                                   Date::Increment(1);
                            }
                     }
              }
       }
}
void ClockwithDate::DecrementSecond(int n){   int i;
       for(i=1;i<=n;i++){
              Second--;
              if(Second==-1){
                     Second=59;
                     Minute--;
                     if(Minute==-1){
                            Minute=59;
                            Hour--;
                            if(Hour==-1){
                                   Hour=23;
                                   Date::Decrement(1);
                            }
                     }
              }
       }
}
 
int main(){
       ClockwithDate cd(Date(2007,2,28),Clock(23,59,34),AMPM(2));
       cd.ShowDateandTime();
       cd.IncrementSecond(27);
       cd.ShowDateandTime();
       cd.DecrementSecond(27);
       cd.ShowDateandTime();
       return 0;
}

评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

飞赴

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值