[C++进阶]继承和多态的选择题

1.下面关于继承说法不正确的是( )

A.继承可以使用现有类的所有功能,并在无需重新编写原来类的情况下对这些功能进行扩展

B.继承体系中子类必须要体现出与基类的不同

C.子类对象一定比基类对象大

D.继承呈现了面相对象程序设计的层次结构,体现了有简单到复杂的认知过程

这题选择:C

解析:

A.这是继承的功能,也是代码复用的体现

B.继承除了吸收基类成员之外,一般还需要扩充自己的数据成员,跟基类有所不一样

C.不一定,有可能子类只是改写父类的方法而已,并没有增加其自身的数据成员,则大小一样,故错误

D.继承体现了一定的层次结构和认知过程

2.关于继承说法正确的是( )

A.所有的类都可以被继承

B.Car(汽车)类和Tire(轮胎)类可以使用继承方式体现

C.继承是实现代码复用的唯一手段

D.狗是一种动物,可以体现出继承的思想

这题选择:D

解析:

A.final说明的类不能被继承

B.应该使用组合,因为Tire类跟Car类属于Has-a的关系

C.模板也是代码复用的手段

D.狗是动物的一种,属于is-a关系,是继承的体现

3.下面关于继承权限说法正确的是( )

A.派生类在继承基类时,必须明确指定继承方式

B.Class定义的类,默认的访问权限是protected

C.struct定义的类,默认访问权限是public

D.子类没有继承基类私有的成员

这题选择:C

解析:

A.可以不指定,默认为private

B.Class定义的类,默认的访问权限是private

C.正确,在C++中,这是struct跟class唯一的区别

D. 私有的成员继承下来了,但是在子类中不可见

4.下面关于访问权限与继承权限说法不正确的是( )

A.访问权限和继承权限是不同的概念

B.访问权限和继承权限关键字上是一样的,但是出现位置不一样

C.如果是protected继承方式,基类public的成员变量能通过基类对象在类外直接访问

D.基类私有的成员变量在子类中都不能直接访问,因为没有被子类继承了

这题选:D

解析:

A.两个权限控制的东西不一样

B.访问权限在类内部,继承权限在类外

C.只要是public成员对象都可以直接访问

D.基类私有成员不能直接访问不是没有被继承,而是权限问题

5.关于同名隐藏的说法正确的是( )

A.同一个类中,不能存在相同名称的成员函数

B.在基类和子类中,可以存在相同名称但参数列表不同的函数,他们形成重载

C.在基类和子类中,不能存在函数原型完全相同的函数,因为编译时会报错

D.成员函数可以同名,只要参数类型不同即可,成员变量不能同名,即使类型不同

这题选:D

解析:

A.可以存在,如函数重载

B.基类与子类函数名字相同,参数不同,形成的是隐藏

C.可以共存

D.成员函数在同一个类里面同名,此时构成了重载,但变量一定不能同名,故正确

6.下面代码输出结果:( )

class A
{
public:
  void f(){ cout<<"A::f()"<<endl; }
  int a;   
};
class B : public A
{
public:
  void f(int a){cout<<"B::f()"<<endl;}
  int a;
};
int main()
{
  B b;
  b.f();
  return 0;
}

A.打印A::f()

B.打印B::f()

C.不能通过编译,因为基类和派生类中a的类型以及名称完全相同

D.以上说法都不对

这题选择:D

解析:

A.错误

B.错误

C.不能通过编译是正确的,不过原因不是因为成员变量a的问题,而是子类同名隐藏了父类方法的原因

D.很显然以上说法都不对

7.下面说法正确的是( )

A.派生类构造函数初始化列表的位置必须显式调用基类的构造函数,已完成基类部分成员的初始化

B.派生类构造函数先初始化子类成员,再初始化基类成员

C.派生类析构函数不会自动析构基类部分成员

D.子类构造函数的定义有时需要参考基类构造函数

这题选择:D

解析:

A.如果父类有默认构造函数,此时就不需要

B.顺序相反,先初始化父类,再是子类

C.会调用,并且按照构造的相反顺序进行调用

D.是的,需要看父类构造函数是否需要参数子类的,从而你决定子类构造函数的定义

8.下列代码中f函数执行结束后输出( )

class A

{

public:

  A() { cout<<"A::A()"<<endl; }

  ~A() { cout<<"A::~A()"<<endl; }

  int a;

};



class B : public A

{

public:

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

  ~B() {cout<<"B::~B()"<<endl; }

  int b;

};



void f()

{

  B b;

}

A.B::B() B::~B()

B.B::B() A::A() A::~A() B::B()

C.A::A() B::B() B::~B() A::~A()

D.以上都不对

这题选择:C

分析: 子类实例化对象,由于继承的有父类。所以会先构造父类,然后在构造子类,析构顺序完全按照构造的相反顺序进行析构,故答案为 C

9.关于派生类构造函数与析构函数说法正确的是( )

A.在派生类对象构造时,先调用基类构造函数,后调用子类构造函数

B.在派生构造函数初始化列表的位置必须显式调用基类构造函数

C.在派生类对象销毁时,先调用基类析构函数,后调用子类析构函数

D.派生类的析构函数只需析构派生类的资源即可

这题选A

A.先构造父类,在构造子类 故正确

B.不一定,如果父类有默认构造函数就不需要

C.刚好相反,先调用子类,在调用父类

D.派生类的析构函数往往还需要连同父类析构函数一起调用,同时清除父类的资源

10.关于基类哪些成员被子类继承说法不正确的是( )

A.静态成员函数

B.所有成员变量

C.基类的友元函数

D.静态成员变量在整个继承体系中只有一份

这题选择C

解析:

A.静态成员函数也可以被继承

B.成员变量所有的都会被继承,无论公有私有

C.友元函数不能被继承,相当于你爹的朋友不一定是你的朋友

D.静态成员属于整个类,不属于任何对象,所以在整体体系中只有一份

11.关于虚函数说法正确的是( )

A.被virtual修饰的函数称为虚函数

B.虚函数的作用是用来实现多态

C.虚函数在类中声明和类外定义时候,都必须加虚拟关键字

D.静态虚成员函数没有this指针

这图选择B

解析:

A.被virtual修饰的成员函数称为虚函数

B.正确

C.virtual关键字只在声明时加上,在类外实现时不能加

D.static和virtual是不能同时使用的

12.关于不能设置成虚函数的说法正确的是( )

A.友元函数可以作为虚函数,因为友元函数出现在类中

B.成员函数都可以设置为虚函数

C.静态成员函数不能设置成虚函数,因为静态成员函数不能被重写

D.析构函数建议设置成虚函数,因为有时可能利用多态方式通过基类指针调用子类析构函数\

这题选D

解析:

A.友元函数不属于成员函数,不能成为虚函数

B.静态成员函数就不能设置为虚函数

C.静态成员函数与具体对象无关,属于整个类,核心关键是没有隐藏的this指针,可以通过类名::成员函数名 直接调用,此时没有this无法拿到虚表,就无法实现多态,因此不能设置为虚函数

D.尤其是父类的析构函数强力建议设置为虚函数,这样动态释放父类指针所指的子类对象时,能够达到析构的多态

13.关于多态,说法不正确的是( )

A.C++语言的多态性分为编译时的多态性和运行时的多态性

B.编译时的多态性可通过函数重载实现

C.运行时的多态性可通过模板和虚函数实现

D.实现运行时多态性的机制称为动态绑定

这题选C

A.多态分为编译时多态和运行时多态,也叫早期绑定和晚期绑定

B.编译时多态是早期绑定,主要通过重载实现

C.模板属于编译时多态,故错误

D.运行时多态是动态绑定,也叫晚期绑定

14.要实现多态类型的调用,必须( )

A.基类和派生类原型相同的函数至少有一个是虚函数即可

B.假设重写成功,通过指针或者引用调用虚函数就可以实现多态

C.在编译期间,通过传递不同类的对象,编译器选择调用不同类的虚函数

D.只有在需要实现多态时,才需要将成员函数设置成虚函数,否则没有必要

这题选D

解析:

A.必须是父类的函数设置为虚函数

B.必须通过父类的指针或者引用才可以,子类的不行

C.不是在编译期,而应该在运行期间,编译期间,编译器主要检测代码是否违反语法规则,此时无法知道基类的指针或者引用到底引用那个类的对象,也就无法知道调用那个类的虚函数。在程序运行时,才知道具体指向那个类的对象,然后通过虚表调用对应的虚函数,从而实现多态。

D.正确,实现多态是要付出代价的,如虚表,虚表指针等,所以不实现多态就不要有虚函数了

15.关于重载、重写和重定义的区别说法正确的是( )【不定项选择】\

A.重写和重定义都发生在继承体系中

B.重载既可以在一个类中,也可以在继承体系中

C.它们都要求原型相同

D.重写就是重定义

E.重定义就是重写

F.重写比重定义条件更严格

G.以上说法全错误

这题选:AF

解析:

A.重写即覆盖,针对多态, 重定义即隐藏, 两者都发生在继承体系中

B.重载只能在一个范围内,不能在不同的类里

C.只有重写要求原型相同

D.重写和重定义是两码事,重写即覆盖,针对多态, 重定义即隐藏

E.重写和重定义是两码事,重写即覆盖,针对多态, 重定义即隐藏

F.重写要求函数完全相同,重定义只需函数名相同即可

G.很明显有说法正确的答案

16.关于重载和多态正确的是 ( )

A.如果父类和子类都有相同的方法,参数个数不同, 将子类对象赋给父类对象后, 采用父类对象调用该同名方法时,实际调用的是子类的方法

B.选项全部都不正确

C.重载和多态在C++面向对象编程中经常用到的方法,都只在实现子类的方法时才会使用

D.class A{ public: void test(float a) { cout << a; } }; class B :public A{ public: void test(int b){ cout << b; } }; void main() { A *a = new A; B *b = new B; a = b; a->test(1.1); } 结果是1

这题选B

解析:

A.使用父类对象调用的方法永远是父类的方法

B.正确

C.重载不涉及子类

D.输入结果为1.1

17.以下哪项说法时正确的( )

class A

{

public:

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

  virtual void f2(){cout<<"A::f2()"<<endl;}

  virtual void f3(){cout<<"A::f3()"<<endl;}

};



class B : public A

{

public:

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

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

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

};

A.基类和子类的f1函数构成重写

B.基类和子类的f3函数没有构成重写,因为子类f3前没有增加virtual关键字

C.基类引用引用子类对象后,通过基类对象调用f2时,调用的是子类的f2

D.f2和f3都是重写,f1是重定义

这题选D

解析:

A.错误,构成重写是子类重写父类的virtual函数,

B.f3构成重写,重写时子类可以不要求加virtual关键字

C. 选择题一定要扣字眼,题目前半句说的是基类引用 引用了子类对象,但是后半句调用虚函数时,说的是基类的对象调用f2,通过对象调用时编译期间就直接确定调用那个函数了,不会通过虚表以多态方式调用

D.正确

18.关于抽象类和纯虚函数的描述中,错误的是 ( )

A.纯虚函数的声明以“=0;”结束

B.有纯虚函数的类叫抽象类,它不能用来定义对象

C.抽象类的派生类如果不实现纯虚函数,它也是抽象类

D.纯虚函数不能有函数体

这题选D

A.纯虚函数的声明以“=0;”结束,这是语法要求

B.有纯虚函数的类叫抽象类,它不能用来定义对象,一般用于接口的定义

C.子类不实现父类所有的纯虚函数,则子类还属于抽象类,仍然不能实例化对象

D.纯虚函数可以有函数体,只是意义不大

19.假设A为抽象类,下列声明( )是正确的

A.A fun(int);

B.A*p;

C.int fun(A);

D.A obj;

这题选B

解析:

A.抽象类不能实例化对象,所以以对象返回是错误

B.抽象类可以定义指针,而且经常这样做,其目的就是用父类指针指向子类从而实现多态

C.参数为对象,所以错误

D.直接实例化对象,这是不允许的

20.关于虚表说法正确的是( )

A.一个类只能有一张虚表

B.基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表

C.虚表是在运行期间动态生成的

D.一个类的不同对象共享该类的虚表

这题选D

A.多继承的时候,就会可能有多张虚表

B.父类对象的虚表与子类对象的虚表没有任何关系,这是两个不同的对象

C.虚表是在编译期间生成的

D.一个类的不同对象共享该类的虚表,可以自行写代码验证之

21.下面函数输出结果是( )

class A

{

public: 

  virtual void f()

  {

    cout<<"A::f()"<<endl;

  }

};



class B : public A

{

private:

   virtual void f()

  {

    cout<<"B::f()"<<endl;

  }

};



A* pa = (A*)new B;

pa->f();

A.B::f()

B.A::f(),因为子类的f()函数是私有的

C.A::f(),因为强制类型转化后,生成一个基类的临时对象,pa实际指向的是一个基类的临时对象

D.编译错误,私有的成员函数不能在类外调用

这题选择:A

解析:

A.正确

B.虽然子类函数为私有,但是多态仅仅是用子类函数的地址覆盖虚表,最终调用的位置不变,只是执行函数发生变化

C.不强制也可以直接赋值,因为赋值兼容规则作出了保证

D.编译正确

22.如果类B继承类A,A::x()被声明为虚函数,B::x()重写了A::x()方法,下述语句中哪个x()方法会被调用:( )

B b;

b.x();

A.A::x()

B.B::x()

C.A::x() B::x()

D.B::x() A::x()

这题选B

解析:虽然子类重写了父类的虚函数,但只要是用对象去调用,则只能调用相对类型的方法,故B正确

23.以下程序输出结果是( )

class A

{

public:

  A ():m_iVal(0){test();}

  virtual void func() { std::cout<<m_iVal<<‘ ’;}

  void test(){func();}

public:

  int m_iVal;

};



class B : public A

{

public:

  B(){test();}

  virtual void func()

  {

    ++m_iVal;

    std::cout<<m_iVal<<‘ ’;

  }

};



int main(int argc ,char* argv[])

{

  A*p = new B;

  p->test();

  return 0;

}

A.1 0

B.0 1

C.0 1 2

D.2 1 0

E.不可预期

F. 以上都不对

这题选C

解析:

1.C++继承体系中构造函数的调用顺序。

2.构造函数中调用虚函数问题。

C++继承体系中,初始化时构造函数的调用顺序如下

(1)任何虚拟基类的构造函数按照他们被继承的顺序构造

(2)任何非虚拟基类的构造函数按照他们被继承的顺序构造

(3)任何成员对象的函数按照他们声明的顺序构造

(4)类自己的构造函数

据此可知 A*p = newB;先调用A类的构造函数再调用B类的构造函数。

构造函数中调用虚函数,虚函数表现为该类中虚函数的行为,即在父类构造函数中调用虚函数,虚函数的表现就是父类定义的函数的表现。why?原因如下:

假设构造函数中调用虚函数,表现为普通的虚函数调用行为,即虚函数会表现为相应的子类函数行为,并且假设子类存在一个成员变量int a;子类定义的虚函数的新的行为会操作a变量,在子类初始化时根据构造函数调用顺序会首先调用父类构造函数,那么虚函数回去操作a,而因为a是子类成员变量,这时a尚未初始化,这是一种危险的行为,作为一种明智的选择应该禁止这种行为。所以虚函数会被解释到基类而不是子类。

据此可以得到答案C正确

解析思路来源链接:以下程序输出结果是______牛客网

24.假设A类中有虚函数,B继承自A,B重写A中的虚函数,也没有定义任何虚函数,则( )

A.A类对象的前4个字节存储虚表地址,B类对象前4个字节不是虚表地址

B.A类对象和B类对象前4个字节存储的都是虚表的地址

C.A类对象和B类对象前4个字节存储的虚表地址相同

D.A类和B类中的内容完全一样,但是A类和B类使用的不是同一张虚表

这题选B

解析:

A.父类对象和子类对象的前4字节都是虚表地址

B.A类对象和B类对象前4个字节存储的都是虚表的地址,只是各自指向各自的虚表

C.不相同,各自有各自的虚表

D.A类和B类不是同一类内容不同

25.假设D类先继承B1,然后继承B2,B1和B2基类均包含虚函数,D类对B1和B2基类的虚函数重写了,并且D类增加了新的虚函数,则( )

A.D类对象模型中包含了3个虚表指针

B.D类对象有两个虚表,D类新增加的虚函数放在第一张虚表最后

C.D类对象有两个虚表,D类新增加的虚函数放在第二张虚表最后

D.以上全部错误

这题选择:B

解析:

A.D类有几个父类,如果父类有虚函数,则就会有几张虚表,自身子类不会产生多余的虚表,所以只有2张虚表

B.正确

C.子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用

D.错误

  • 26
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值