这一章主要是对C++多态——点我可以了解章节的具体应用,接下来一道一道的来分析:👇👀
1. 关于虚函数说法【正确】的是( B)
A.被virtual修饰的函数称为虚函数
B.虚函数的作用是用来实现多态
C.虚函数在类中声明和类外定义时候,都必须加虚拟关键字
D.静态虚成员函数没有this指针
1:解析:
A:对应知识点是非成员函数不能写为虚函数。因此被virtual修饰的成员函数才是虚函数。
B:虚函数的主要作用没得说了,就是为实现多态而生的。
C:简单来说,virtual关键字只能在声明时加,在类外实现不能加。
D:static和virtual是不能同时使用。
2.关于不能设置成虚函数的说法【正确】的是( D)
A.友元函数可以作为虚函数,因为友元函数出现在类中
B.成员函数都可以设置为虚函数
C.静态成员函数不能设置成虚函数,因为静态成员函数不能被重写
D.析构函数建议设置成虚函数,因为有时可能利用多态方式通过基类指针调用子类析构函数
2:解析:
A:知识点也是只有成员函数才能写为虚函数,因为友元函数不是成员函数。
B:不是所有的成员函数都可以设置为虚函数,静态成员函数是不可以定义为虚函数的。
C:.静态成员函数与具体对象无关,属于整个类,核心关键是没有隐藏的this指针,可以通过类名::
[成员函数名] 直接调用,此时没有this无法拿到虚表,就无法实现多态,因此不能设置为虚函数。
D:在此处尤其是父类的析构函数强烈建议设置为虚函数,因为在动态释放父类指针所指向的子类时,能够达到析构的多态。
3.关于多态,说法不正确的是(C )
A.C++语言的多态性分为编译时的多态性和运行时的多态性
B.编译时的多态性可通过函数重载实现
C.运行时的多态性可通过模板和虚函数实现
D.实现运行时多态性的机制称为动态绑定
3:解析:
C:模版是在编译时确定的属于编译时多态,故错误了。
4.要实现多态类型的调用,必须(C )
A.基类和派生类原型相同的函数至少有一个是虚函数即可
B.假设重写成功,通过指针或者引用调用虚函数就可以实现多态
C.在编译期间,通过传递不同类的对象,编译器选择调用不同类的虚函数
D.只有在需要实现多态时,才需要将成员函数设置成虚函数,否则没有必要
4:解析:
A:前提条件是要父类的那个函数要是虚函数才可以。
B:必须通过父类的指针或引用来调用虚函数,才可以实现多态。
C:不是在编译期,而应该在运行期间,编译期间,编译器主要检测代码是否违反语法规则,此时无法知道基类的指针或者引用到底引用那个类的对象,也就无法知道调用那个类的虚函数。在程序运行时,才知道具体指向那个类的对象, 然后通过虚表调用对应的虚函数,从而实现多态。
D:.正确,实现多态是要付出代价的,如虚表,虚表指针等,所以不实现多态就不要有虚函数了
5.关于重载、重写和重定义的区别说法【正确】的是(A、F )【多选哦】
A.重写和重定义都发生在继承体系中
B.重载既可以在一个类中,也可以在继承体系中
C.它们都要求原型相同
D.重写就是重定义
E.重定义就是重写
F.重写比重定义条件更严格
G.以上说法全错误
5:解析:
A:重写即覆盖,针对多态, 重定义即隐藏, 两者都发生在继承体系中。
B:重载只能在一个范围内,不能在不同的类里。
C:只有重写要求原型相同。
D/E:重写和重定义是两码事,重写即覆盖,针对多态, 重定义即隐藏。
F:重写要求函数完全相同,重定义只需函数名相同即可。
6.关于重载和多态【正确】的是(B )
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
6:解析:
A:使用父类的对象调用函数,永远是父类的函数(方法)。
C:重载是不涉及子类的,只需要在同一作用于就可以了。
D:a是父类的对象,调用函数还是父类的函数(方法)。
7.以下哪项说法时【正确】的(D )
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是重定义
7:解析:
A:错误,构成重写是子类重写父类的虚函数。
B:构成重写,因为派生类在重写基类虚函数的时候,可以省略关键字virtual。
C:题目前半句说的是基类引用 引用了子类对象,但是后半句调用虚函数时,说的是基类的对象调用f2,通过对象调用时编译期间就直接确定调用那个函数了,不会通过虚表以多态方式调用。基类对象调用函数,依然是基类里面对应的函数。
==8.关于抽象类和纯虚函数的描述中,【错误】的是 (D )
A.纯虚函数的声明以“=0;”结束
B.有纯虚函数的类叫抽象类,它不能用来定义对象
C.抽象类的派生类如果不实现纯虚函数,它也是抽象类
D.纯虚函数不能有函数体
8:解析:
A.纯虚函数的声明以“=0;”结束,这是语法要求。
B.有纯虚函数的类叫抽象类,它不能用来定义对象,一般用于接口的定义。
C.子类不实现父类所有的纯虚函数,则子类还属于抽象类,仍然不能实例化对象。
D.纯虚函数可以有函数体,只是意义不大。
9.假设A为抽象类,下列声明【正确】的是(B)
A.A fun(int);
B.A*p;
C.int fun(A);
D.A obj;
9:解析:
A.抽象类不能实例化对象,所以以对象返回是错误
B.抽象类可以定义指针,而且经常这样做,其目的就是用父类指针指向子类从而实现多态
C.参数为对象,所以错误
D.直接实例化对象,这是不允许的
10.关于虚表说法正确的是( D)
A.一个类只能有一张虚表
B.基类中有虚函数,如果子类中没有重写基类的虚函数,此时子类与基类共用同一张虚表
C.虚表是在运行期间动态生成的
D.一个类的不同对象共享该类的虚表
10:解析:
A.多继承的时候,就会可能有多张虚表。
B.父类对象的虚表与子类对象的虚表没有任何关系,这是两个不同的对象。
C.虚表是在编译期间生成的。
D.一个类的不同对象共享该类的虚表。
11.下面函数输出结果是( A)
class A
{
public:
virtual void f()
{
cout<<“A::f()”<<endl;
}
};
class B : public A
{
private:
virtual void f()
{
cout<<“B::f()”<<endl;
}
};
int main()
{
A* pa = (A*)new B;
pa->f();
return 0;
}
A.B::f()
B.A::f(),因为子类的f()函数是私有的
C.A::f(),因为强制类型转化后,生成一个基类的临时对象,pa实际指向的是一个基类的临时对象
D.编译错误,私有的成员函数不能在类外调用
11:解析:
首先从主函数中可以看到是基类的指针调用的函数。并且该函数是构成多态的,因此指向谁调用谁,所以是B::f()
A.正确
B.虽然子类函数为私有,但是多态仅仅是用子类函数的地址覆盖虚表,最终调用的位置不变,只是执行函数发生变化
C.不强制也可以直接赋值,因为赋值兼容规则作出了保证
D.编译是正确的
12.如果类B继承类A,A::x()被声明为虚函数,B::x()重写了A::x()方法,下述语句中 哪个x()方法会被调用:( B)
B b; b.x();
A.A::x()
B.B::x()
C.A::x() B::x()
D.B::x() A::x()
12:解析:
虽然子类重写了父类的虚函数,但只要是用对象去调用,则只能调用相对类型的方法。也就是说不符合多态的用基类指针或引用调用函数。
13.以下程序输出结果是(C )
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. 以上都不对
13:解析:
new B时先调用父类A的构造函数,执行test()函数,在调用func()函数,由于此时还处于对象构造阶段,多态机制还没有生效,所以,此时执行的func函数为父类的func函数,打印0,构造完父类后执行子类构造函数,又调用test函数,然后又执行func(),由于父类已经构造完毕,虚表已经生成,func满足多态的条件,所以调用子类的func函数,对成员m_iVal加1,进行打印,所以打印1, 最终通过父类指针p->test(),也是执行子类的func,所以会增加m_iVal的值,最终打印2, 所以答案为C: 0 1 2
14.假设A类中有虚函数,B继承自A,B重写A中的虚函数,也没有定义任何虚函数,则( B)
A.A类对象的前4个字节存储虚表地址,B类对象前4个字节不是虚表地址
B.A类对象和B类对象前4个字节存储的都是虚表的地址
C.A类对象和B类对象前4个字节存储的虚表地址相同
D.A类和B类中的内容完全一样,但是A类和B类使用的不是同一张虚表
14:解析;
A.父类对象和子类对象的前4字节都是虚表地址
B.A类对象和B类对象前4个字节存储的都是虚表的地址,只是各自指向各自的虚表
C.不相同,各自有各自的虚表
D.A类和B类不是同一类内容不同
15.假设D类先继承B1,然后继承B2,B1和B2基类均包含虚函数,D类对B1和B2基类的虚函数重写了,并且D类增加了新的虚函数,则:(B )
A.D类对象模型中包含了3个虚表指针
B.D类对象有两个虚表,D类新增加的虚函数放在第一张虚表最后
C.D类对象有两个虚表,D类新增加的虚函数放在第二张虚表最后
D.以上全部错误
15:解析:
A.D类有几个父类,如果父类有虚函数,则就会有几张虚表,自身子类不会产生多余的虚表,所以只有2张虚表
B.正确
C.子类自己的虚函数只会放到第一个父类的虚表后面,其他父类的虚表不需要存储,因为存储了也不能调用
D.错误