【C++】继承与多态的一些练习题

学习完了继承与多态,当然要来点练习题啦~

第一题:

class Base1 {  public:  int _b1; };
class Base2 {  public:  int _b2; };
class Derive : public Base1, public Base2 { public: int _d; };
int main(){
Derive d;
Base1* p1 = &d;
Base2* p2 = &d;
Derive* p3 = &d;
return 0;
}

在这里插入图片描述
答案:C
解析:先继承的先声明,先声明的先在前。
在这里插入图片描述

第二题:

打印的顺序是什么?

class A {
public:
	A(const char* s) { cout << s << endl; }
	~A() {}
	int _a;
};
class B :virtual public A
{
public:
	B(const char* s1, const char* s2) :A(s1) { cout << s2 << endl; }
	int _b;
};
class C :virtual public A
{
public:
	C(const char* s1, const char* s2) :A(s1) { cout << s2 << endl; }
	int _c;
};
class D :public B, public C
{
public:
	D(const char* s1, const char* s2, const char* s3, const char* s4) :B(s1, s2), C(s1, s3), A(s1)
	{
		cout << s4 << endl;
	}
	int _d;
};
int main() {
	D* p = new D("class A", "class B", "class C", "class D");
	delete p;
	return 0;
}

答案:在这里插入图片描述

解释:由于我们使用了虚继承,那么就意味着只有一个A,在VS中,这个A一般在对象的末尾。

在这里插入图片描述
只有一个A的话那么初始化时只会初始化一次,但是我们的程序中一共调用了3次A的构造,在那个地方初始化呢?注意:我们的A是最先继承的,所以也是最先声明的(由于是虚继承,所以A的位置就不一定放在对象的最前边,由编译器决定),所以在一开始就会先初始化最先声明的,也就是先初始化A,然后是B与C在声明,所以在打印B与C,最后走完D的初始化列表,再打印D。

第三题:

打印的是什么呢?

class A
{
public:
	virtual void func(int val = 1) { std::cout << "A->" << val << std::endl; }
	virtual void test() { func(); }
};
class B : public A
{
public:
	void func(int val = 0) { std::cout << "B->" << val << std::endl; }
};
int main(int argc, char* argv[])
{
	B* p = new B;
	p->test();
	return 0;
}

答案:
在这里插入图片描述
解析:首先我们对func函数完成了重写,为什么呢?
子类的virtual可以不写,不必多说
可能有人会疑惑,参数不同啊,非也非也,我们在多态这说的参数是类型,并不是数值。
此外,我们虚函数的重写是对实现的重写,对接口是直接继承的,这也是我们重写名字的由来(覆盖是语法层的概念)

现在我们就可以正式的来解决这道问题了。
我们使用p调用test函数,注意是继承A的test函数,所以此时p发生切片变为A*,也就是this指针,我们使用指针父类指针调用,所以此时就构成了多态
所以调用的就是B的func,注意我们已经说了我们重写重写的是实现,继承的是接口,所以我们的val为1,所以我们就解决了这道问题!

一些面试题:

  1. 什么是多态?答:具体点就是去完成某个行为,当不同的对象去完成时会产生出不同的状态。

  2. 什么是重载、重写(覆盖)、重定义(隐藏)?答:在这里插入图片描述

  3. 多态的实现原理?答:虚表指针与虚函数,由父类指针调用函数时,运行时会去虚表中找对应的虚函数,从而实现不同的行为

  4. inline函数可以是虚函数吗?答:表层来看:内联函数没有属于自己的地址,而虚函数地址要被放到虚表中,所以不可以是虚函数。 深层:通过编译,我们知道是可以的,首先我们要明确内联只是一个建议:当一个虚函数被声明为内联时,如果没有构成多态,编译器允许的情况下就会展开;如果构成多态,那么就无视inline,转而执行多态的行为

  5. 静态成员可以是虚函数吗?答:不能,因为静态成员函数没有this指针,使用类型::成员函数的调用方式无法访问虚函数表,所以静态成员函数无法放进虚函数表。

  6. 构造函数可以是虚函数吗?答:我们可以从两个维度理解:1.不能,因为对象中的虚函数表指针是在构造函数初始化列表阶段才初始化的。2.派生类的构造会显示调用父类的构造函数,而若定义为虚函数那么只能只向谁调谁,显然不符合常理,在C++primer中也给这种情况起了名字,具体叫啥忘记了~注意:拷贝也是同理,但是赋值的话对应第二种情况。

  7. 析构函数可以是虚函数吗?什么场景下析构函数是虚函数?答:可以,并且最好把基类的析构函数定义成虚函数。

  8. 对象访问普通函数快还是虚函数更快?答:首先如果是普通对象,是一样快的。如果是指针对象或者是引用对象,则调用的普通函数快,因为构成多态调用,运行时调用虚函数需要到虚函数表中去查找。(由下图可见并不一定是构成多态才会多态调用,如果没有重写依旧会多态调用)在这里插入图片描述
    在这里插入图片描述

  9. 虚函数表是在什么阶段生成的,存在哪的?答:虚函数表是在编译阶段就生成的,一般情况下存在代码段(常量区)的。

  10. 什么是抽象类?抽象类的作用?答:抽象类强制重写了虚函数,另外抽象类体现出了接口继承关系。

后续也会继续更新!

  • 31
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为你提供一个简单的继承与多练习题,希望能帮助你巩固相关知识。 假设有一个图形类 Shape,其中包含一个纯虚函数 getArea(),用于计算该图形的面积。现在要定义两个子类,分别是矩形类 Rectangle 和圆形类 Circle。请完成以下任务: 1. 定义 Shape 类: ```c++ class Shape { public: virtual double getArea() = 0; // 纯虚函数 }; ``` 2. 定义 Rectangle 类,继承自 Shape 类,包含两个成员变量 width 和 height,以及实现 getArea() 函数的具体方法: ```c++ class Rectangle : public Shape { private: double width; double height; public: Rectangle(double w, double h) { width = w; height = h; } double getArea() { return width * height; } }; ``` 3. 定义 Circle 类,同样继承自 Shape 类,包含一个成员变量 radius,以及实现 getArea() 函数的具体方法: ```c++ class Circle : public Shape { private: double radius; public: Circle(double r) { radius = r; } double getArea() { return 3.1415926 * radius * radius; } }; ``` 4. 在主函数中创建一个 Shape 指针数组,分别指向一个 Rectangle 和一个 Circle 对象,并计算它们的面积: ```c++ int main() { Shape* shapes[2]; shapes[0] = new Rectangle(4, 5); shapes[1] = new Circle(3); for (int i = 0; i < 2; i++) { cout << "Area of shape " << i << ": " << shapes[i]->getArea() << endl; delete shapes[i]; } return 0; } ``` 以上就是一个简单的继承与多练习题,希望能够帮助你巩固相关知识。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值