• C++:继承作业题


    1.

         关于以下菱形继承说法不正确的是( )

    1. class B {public: int b;};
    2. class C1: public B {public: int c1;};
    3. class C2: public B {public: int c2;};
    4. class D : public C1, public C2 {public: int d;};
    5. A.D总共占了20个字节
    6. B.B中的内容总共在D对象中存储了两份
    7. C.D对象可以直接访问从基类继承的b成员
    8. D.菱形继承存在二义性问题,尽量避免设计菱形继承

         解析:A.C1中b和c1共8个字节,C2中c2和b共8个字节,D自身成员d 4个字节,一共20个字节

         B. 由于菱形继承,B的内容在D中有两份

         C.子类对象不能直接访问最顶层基类B中继承下来的b成员,因为在D对象中,b是有两份的,一份从C1中继承,一份从C2中继承,直接通过D的对象访问b会存在二义性问题,在访问的时候,通过加类名::b,来访问C1或者C2从基类继承下来的b

         D.菱形继承存在二义性问题,尽量避免设计菱形继承,如果真需要,一般采用虚拟继承来减少数据冗余

    2.

        关于基类与子类对象之间赋值说法不正确的是( )

    1. A.基类指针可以直接指向子类对象
    2. B.基类对象可以直接赋值给子类对象
    3. C.子类对象的引用不能引用基类的对象
    4. D.子类对象可以直接赋值给基类对象

         解析:该题考查了在继承关系在的基类和派生类的切片和内存模型,p1和p2虽然都是指向基类对象的指针,但在派生类内存模型中,其位置不同,所以p1和p2所指子类的位置也不相同,所以p1!=p2;由于p1对象是第一个被继承的父类类型,其地址与子类对象的地址p3所指位置都是子类对象的起始位置,所以p1=p3。

    3.

         关于基类与子类对象之间赋值说法不正确的是( )

    1. A.基类指针可以直接指向子类对象
    2. B.基类对象可以直接赋值给子类对象
    3. C.子类对象的引用不能引用基类的对象
    4. D.子类对象可以直接赋值给基类对象

         解析:A.赋值兼容

                    B.基类对象不能给子类对象赋值,因为子类对象有的基类对象没有

                    C.不能用父类初始化子类引用,因为子类有的父类没有

                    D.赋值兼容

    4.

         关于基类与派生类对象模型说法正确的是()

    1. A.基类对象中包含了所有基类的成员变量
    2. B.子类对象中不仅包含了所有基类成员变量,也包含了所有子类成员变量
    3. C.子类对象中没有包含基类的私有成员
    4. D.基类的静态成员可以不包含在子类对象中
    5. E.以上说法都不对

         解析:A.静态成员变量属于类,所有对象共享同一份数据

                 B.同A

                 C.父类所有成员都会继承到子类,但是子类不能访问,只能通过父类的函数或者类作用域来访问

                 D.静态成员一定是不包含在子类对象中的

    5.

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

    1. A.被virtual修饰的函数称为虚函数
    2. B.虚函数的作用是用来实现多态
    3. C.虚函数在类中声明和类外定义时候,都必须加虚拟关键字
    4. D.静态虚成员函数没有this指针

         解析:A.被virtual修饰的成员函数才是虚函数

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

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

                 D.友元函数(不是成员函数) 构造函数 static静态函数 不能用virtual关键字修饰;

    6.

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

    1. A.友元函数可以作为虚函数,因为友元函数出现在类中
    2. B.成员函数都可以设置为虚函数
    3. C.静态成员函数不能设置成虚函数,因为静态成员函数不能被重写
    4. D.析构函数建议设置成虚函数,因为有时可能利用多态方式通过基类指针调用子类析构函数

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

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

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

                D.基类的析构函数建议设为虚函数,这样动态释放父类指针所指针的子类对象时,能够达到析构的目的

    7.

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

    1. A.C++语言的多态性分为编译时的多态性和运行时的多态性
    2. B.编译时的多态性可通过函数重载实现
    3. C.运行时的多态性可通过模板和虚函数实现
    4. D.实现运行时多态性的机制称为动态绑定

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

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

                 C.模板属于编译时多态

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

    8.

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

    1. A.重写和重定义都发生在继承体系中
    2. B.重载既可以在一个类中,也可以在继承体系中
    3. C.它们都要求原型相同
    4. D.重写就是重定义
    5. E.重定义就是重写
    6. F.重写比重定义条件更严格
    7. G.以上说法全错误

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

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

                 C.重写要求原型相同

                  D,E.重写是覆盖,针对多态,重定义是隐藏

                  F.重写比重定义要求更严格

    9.

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

    1. A.基类和派生类原型相同的函数至少有一个是虚函数即可
    2. B.假设重写成功,通过指针或者引用调用虚函数就可以实现多态
    3. C.在编译期间,通过传递不同类的对象,编译器选择调用不同类的虚函数
    4. D.只有在需要实现多态时,才需要将成员函数设置成虚函数,否则没有必要

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

                 B.必须通过父类的指针或者引用来调用才可以实现多态

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

                 D.虚表和虚表指针等是占用内存空间的,如果不实现多态,没有必要将成员函数设置为虚函数

    10.

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

    1. A.如果父类和子类都有相同的方法,参数个数不同, 将子类对象赋给父类对象后, 采用父类对象调用该同名方法时,实际调用的是子类的方法
    2. B.选项全部都不正确
    3. C.重载和多态在C++面向对象编程中经常用到的方法,都只在实现子类的方法时才会使用
    4. D.
    5. class A
    6. {
    7. public:
    8. void test(float a) { cout << a; }
    9. };
    10. class B :public A
    11. {
    12. public:
    13. void test(int b){ cout << b; }
    14. };
    15. void main()
    16. {
    17. A *a = new A;
    18. B *b = new B;
    19. a = b;
    20. a->test(1.1);
    21. }
    22. 结果是1

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

                  C.重载不涉及子类

                  D.a=b,使得指向B的部分的A的值赋值给A,指针a指向A对象,调用test方法是A对象的方法,故结果是1.1

    11.

         以下哪项说法是正确的( )

    1. class A
    2. {
    3. public:
    4.   void f1(){cout<<"A::f1()"<<endl;}
    5.   virtual void f2(){cout<<"A::f2()"<<endl;}
    6.   virtual void f3(){cout<<"A::f3()"<<endl;}
    7. };
    8. class B : public A
    9. {
    10. public:
    11.   virtual void f1(){cout<<"B::f1()"<<endl;}
    12.   virtual void f2(){cout<<"B::f2()"<<endl;}
    13.   void f3(){cout<<"B::f3()"<<endl;}
    14. };
    15. A.基类和子类的f1函数构成重写
    16. B.基类和子类的f3函数没有构成重写,因为子类f3前没有增加virtual关键字
    17. C.基类引用引用子类对象后,通过基类对象调用f2时,调用的是子类的f2
    18. D.f2和f3都是重写,f1是重定义

         解析:A.错误,构成重写的要求是父类的函数是虚函数

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

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

    12.

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

    1. A.一个类只能有一张虚表
    2. B.基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表
    3. C.虚表是在运行期间动态生成的
    4. D.一个类的不同对象共享该类的虚表

          解析:A.多继承时,可能会有多张虚表

                  B.父类对象的虚表和子类对象的虚表没有关系

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

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

    13.

         下面函数输出结果是( )

    1. class A
    2. {
    3. public
    4.   virtual void f()
    5.   {
    6.     cout<<"A::f()"<
    7.   }
    8. };
    9. class B : public A
    10. {
    11. private:
    12.    virtual void f()
    13.   {
    14.     cout<<"B::f()"<
    15.   }
    16. };
    17. A* pa = (A*)new B;
    18. pa->f();

         解析:A.正确

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

                  C.不强制也可以直接赋值,因为有赋值兼容规则

    14.

    1. 如果类B继承类A,A::x()被声明为虚函数,B::x()重写了A::x()方法,下述语句中哪个x()方法会被调用:( )
    2. B b;
    3. b.x();
    4. A.A::x()
    5. B.B::x()
    6. C.A::x() B::x()
    7. D.B::x() A::x()

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

    15.

    1. 以下程序输出结果是( )
    2. class A
    3. {
    4. public:
    5. A ():m_iVal(0){test();}
    6. virtual void func() { std::cout<<m_iVal<<‘ ’;}
    7. void test(){func();}
    8. public:
    9. int m_iVal;
    10. };
    11. class B : public A
    12. {
    13. public:
    14. B(){test();}
    15. virtual void func()
    16. {
    17. ++m_iVal;
    18. std::cout<<m_iVal<<‘ ’;
    19. }
    20. };
    21. int main(int argc ,char* argv[])
    22. {
    23. A*p = new B;
    24. p->test();
    25. return 0;
    26. }

         解析:new B时先调用父类A的构造函数,执行test()函数,在调用fun()函数,此时还在构造对象,多态没有生效,此时执行父类的func函数,打印0,构造完父类后执行子类构造函数,调用test函数,执行func函数,父类此时构造完毕,虚表生成,func满足多态的条件,调用子类的func函数,对成员m_iVal加1,打印1,最终通过父类指针p->test(),执行子类的func,增加m_iVal的值,打印2

  • 相关阅读:
    python反序列化分析
    Go的安装及环境变量的配置
    tensorflow基础
    git push的详细使用
    IntelliJ IDEA中构建Spring Boot的项目
    数据结构-图的深度优先遍历方式(非递归,领接表存储)
    发布Python包到pypi
    澳门服务器有哪些特点
    EasyCode介绍及自定义模板
    微信小程序订单页面怎么写啊,刚开始接触这个自己没有头绪不知道怎么下手
  • 原文地址:https://blog.csdn.net/pancodearea/article/details/137979076