C++ 多态

题目

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

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

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

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

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

  • B

A.只有成员函数才能加 virtual,全局函数不允许加 virtual

B.正确

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

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

为什么静态函数不能是虚函数? 因为虚函数的调用机制要求对象实例,而静态函数完全绕过了对象实例。

  1. 虚函数需要对象的 vptr 来查找虚表中的函数地址 而静态函数没有对象 → 没有 vptr → 无法访问虚函数表。

  2. 静态函数没有 this 指针 虚函数几乎总是通过 this 指针进行行为差异(因为它基于对象类型)

没有 this 就没有虚函数的意义

  1. 编译器不支持,语法上直接报错
  1. 关于不能设置成虚函数的说法正确的是( )

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

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

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

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

  • D

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

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

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

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

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

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

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

C.它们都要求原型相同

D.重写就是重定义

E.重定义就是重写

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

G.以上说法全错误

  • A、F

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

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

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

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

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

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

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

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

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.

参数个数不同 → 属于 函数重载,不是重写(override)

在 C++ 中,子类的同名函数会隐藏(hide)父类的同名函数,即使参数不同

并且当你用 父类对象或指针调用该函数时,只会调用父类的版本

除非父类函数是 virtual 且子类函数签名完全一致,才会触发多态(重写)

D.

分析:

A::test(float) 是定义在基类的函数

B::test(int) 是子类中的新函数,并不是重写父类的函数(参数类型不同)

但!B::test(int) 会隐藏 A::test(float)(名字相同即隐藏,无视参数列表)

然后:

a 是 A* 类型,指向 B 对象

调用 a->test(1.1),编译期只查 A 中的成员

test(float) 存在于 A,参数 1.1 是 double,可转换成 float,合法匹配

最终调用的是 A::test(float),输出是 1.1(或近似浮点)

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

A.A fun(int);

B.A*p;

C.int fun(A);

D.A obj;

  • B

A. A fun(int); 这声明了一个函数 fun,返回类型是 A。

错误:返回类型是抽象类 A,意味着需要返回一个 A 类型的值,这会尝试调用复制构造函数,不允许返回抽象类对象

B. A p;*

正确:抽象类可以作为指针类型声明,因为不涉及构造对象。

通常用于实现多态:A* p = new Derived;

C. int fun(A);

正确:你可以定义一个参数类型为抽象类 A 的函数,尽管你不能传值构造一个 A。

常用于接口设计,尽管实参必须是 A 的子类对象(并传引用更合理)

D. A obj;

错误:抽象类不能定义对象,直接实例化会报错

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

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

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

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

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

  • D

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

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

A.B::f()

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

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

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

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

在 C++ 中,访问控制符(private / protected / public)只约束 "谁能写出调用代码"(即编译期能否访问),而虚函数分发(调用哪个函数实现)发生在运行时,并不受它是否是 private 的影响。

  1. 语法阶段:

pa 是 A* 类型,调用 f() 是合法的(A::f() 是 public)

所以:编译器不会报错

  1. 运行时阶段:

pa 实际指向的是 B 对象

所以查虚函数表,调用 B::f()

即使 B::f() 是 private,编译器不会重新检查访问权限,因为你是通过 A 的接口调用的,访问权限检查已经过去了

学习笔记&amp;练习 文章被收录于专栏

学习过程中的一些记录

全部评论

相关推荐

07-29 17:21
已编辑
华中科技大学 Java
牛客39712426...:华科✌🏻略微**就是我的极限
点赞 评论 收藏
分享
07-30 11:23
门头沟学院 Java
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务