目录
有如下C++代码:
- struct A{
- void foo(){printf("foo");}
- virtual void bar(){printf("bar");}
- A(){bar();}
- };
- struct B:A{
- void foo(){printf("b_foo");}
- void bar(){printf("b_bar");}
- };
- A *p = new B;
- p->foo();
- p->bar();
A barfoob_bar
B foobarb_bar
C barfoob_foo
D foobarb_fpp
这里按照我们运行的逻辑,首先我们new B也就是构造了一个B对象,然后B由于是继承A类的,所以B在构造的时候会调用A的构造函数。
在A的构造函数中有
所以会调用bar()函数,这里是A类的对象调用bar函数,所以不满足多态的条件,所以直接调用A类的bar函数,打印bar
然后由于我们的p是父类A的指针,然后指向的是B类(子类),然后调用foo()方法的时候,由于我们的父类方法的foo前面并没有写virtual,所以并不满足多态的调用条件,所以A类的指针调用A类的方法,也就是打印出foo
然后p->bar()的时候,我们父类A中的bar方法前面有virtual,所以子类的bar()函数前面不写virtual,依然也构成多态,所以这里调用子类的bar方法,也就是打印出b_bar
所以一共打印了barfoob_bar,也就是A
A
以下程序输出结果是()
- class A
- {
- public:
- virtual void func(int val = 1)
- { std::cout<<"A->"<
- virtual void test()
- { func();}
- };
- class B : public A
- {
- public:
- void func(int val=0) {std::cout<<"B->"<
- };
- int main(int argc ,char* argv[])
- {
- B*p = new B;
- p->test();
- return 0;
- }
A A->0
B B->1
C A->1
D B->0
这里我们先初始化了一个B类型的对象,然后用一个B类型的指针指向我们刚刚创建的B类型对象,然后用我们的B类型并且指向B类型对象的指针调用test方法,这里是不满足多态的调用条件的!
但是我们这里的B类中并没有test函数,但是A类中有,并且我们的B类是继承于A类的,所以我们会调用A类中的test函数。
我们的A类中的test函数又调用了func函数,这时,由于我们是A类,所以我们的this指针是A类的,然后我们的当前指针的指向是一个B类的函数,并且这里的func前有virtual,并且子类中也重写了func(),所以是满足多态调用的条件的,所以我们这里会调用子类的func,也就是打印B->
这里的默认值在程序编译时期就已经确定了,而我们的多态是动态调用的,所以没有办法动态更改这个默认值
所以我们的默认值依旧是A类中的func的val,也就是1
所以打印B->1

第三题(纯虚函数的声明)
下列为纯虚函数的正确声明的是()
A void virtual print()=0;
B virtual void print()=0;
C virtual void print(){};
D virtual void print()\;
这里其实A,B都是可以的,但是在习惯上我们写B的写法
C中加了{},已经不算是声明了,还有定义也同时定义了
D本身就是错的,没有这样的写法
B
第四题(多态)
下面这段代码运行时会出现什么问题?
- class A
- {
- public:
- void f()
- {
- printf("A\n");
- }
- };
- class B: public A
- {
- public:
- virtual void f()
- {
- printf("B\n");
- }
- };
- int main()
- {
- A *a = new B;
- a->f();
- delete a;
- return 0;
- }
A 没有问题,输出B
B 不符合预期的输出A
C 程序不正确
D 以上答案都不正确
这里我们子类的构造出了一个对象
这里我们的父类的A指针指向了子类的B对象,然后我们的父类中没有virtual,所以不构成多态。
由于我们的指针是一个父类的指针,所以调用父类的f方法,所以我们打印出A
但是这个程序在空间释放的时候存在问题!
我们怎么产生虚表?
首先我们构造子类的时候,我们会先构造一个父类,但是此时我们的父类没有虚函数,所以它不会有所谓的虚表,只有构造到子类的时候,才会有虚表。
但是虚表的指针往往放在它整个对象的第一个成员,也就是(__vfptr)
但是这个指针又往往会存活于父类部分。
由于这根时候父类没有虚函数,它也就没有办法安插这样的一个虚表指针,但是子类在释放的时候,又需要将它的空间释放掉,这就会导致我们想要释放一些空间,但是父类不提供这样的一些指针,就会导致空间释放的失败。更有可能导致空间的非法访问。
这里我们只要给父类增加一个虚函数,这里的使用就不会有任何问题。因为只要有了虚函数,我们的父类中就会产生虚表,就会给我们提供给子类去用,然后再释放空间的时候就会进行检查。
比方说这样
- class A
- {
- public:
- void f()
- {
- printf("A\n");
- }
- virtual void g()
- {
-
- }
- };
- class B: public A
- {
- public:
- virtual void f()
- {
- printf("B\n");
- }
- };
- int main()
- {
- A *a = new B;
- a->f();
- delete a;
- return 0;
- }
B

第五题(父类的析构函数最好加上virtual!)
下面这段代码会打印出什么?
- class A
- {
- public:
- A()
- {
- printf("A ");
- }
- ~A()
- {
- printf("deA ");
- }
- };
- class B
- {
- public:
- B()
- {
- printf("B ");
- }
- ~B()
- {
- printf("deB ");
- }
- };
- class C: public A, public B
- {
- public:
- C()
- {
- printf("C ");
- }
- ~C()
- {
- printf("deC ");
- }
- };
- int main()
- {
- A *a = new C();
- delete a;
- return 0;
- }
A A B C deA
B C A B deA
C A B C deC
D C A B deC
这里我们构造了一个C的对象,然后C再继承的时候,顺序为A然后再是B

所以先打印A,然后是B,最后是C
然后由于我们的指针的类型是A类型的,所以我们在使用我们的a指针去调用析构函数的时候,
由于我们的A类也就是我们的父类的析构函数并没有加上virtual,所以并不构成多态
所以A类型的指针只能够调用A的析构函数,所以打印出deA
但是我们的B和C并没有正确地被析构!
A
-
相关阅读:
一个练习 k8s 的仓库,通过动手的方式掌握k8s
DT Paint Effects工具(一)
MySQL面试题
十天学完基础数据结构-第七天(图(Graph))
GoLang Map 实现分析
22.2 正则表达式-数据验证、数据变换
Vue3.2开发一个博客Demo项目
K8s如何从私有Harbor中拉取镜像并完成部署
Vue理解之路:如何在Vue项目中使用vuex
ML:置信区间的简介(精密度/准确度/精确度的三者区别及其关系)、使用方法、案例应用之详细攻略
-
原文地址:https://blog.csdn.net/weixin_62684026/article/details/127559683