38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】(二)

简介: 38.【C++ 虚函数 纯虚函数 虚基类 (最全详解)】

【虚函数的调用正中下怀】

代码展示

#include <iostream>
using namespace std;
class A
{
private:
 int number;
public:
 A(int nu=21032114) :number(nu) {}
  virtual void show()
 {
  cout << "基类,学号为:" << number<<endl;
 }
};
class B:public A
{
private:
 int score;
public:
 B(int sc = 86) :score(sc) {}
 void show()
 {
  cout << "派生,成绩为:" << score<<endl;
 }
};
int main()
{
 A a;
 a.show();
 B b;
 b.show();
 A* p;          
 p = &b;
 p->show(); //我想调用派生类,但仍然是基类的函数
 A& p1 = b;    
 b.show();
 return 0;
}

效果展示:

#include using namespace std;

class A { public:

virtual int fun() { return 1; } };

class E : public A { public:

virtual int fun() { return 5; } };

class B : virtual public A { public:

virtual int fun() { return 2; } };

class C : virtual public A { public:

virtual int fun() { return 3; } };

class D : public B, public C { public:

virtual int fun() { return 4; } };

int main() {

cout << sizeof(A) << endl; // 4

cout << sizeof(B) << endl; // 4

cout << sizeof© << endl; // 4

cout << sizeof(D) << endl; // 8

cout << sizeof(E) << endl; // 4

return 0; }

解释:

1.static静态成员变量不需计算

2.成员函数不占用空间

3.虚函数 有一个虚表指针占四个字节

A=4——> 4(A虚表指针)。

4.父类的与子类的同名虚函数,在继承的时候,子类会将父类的覆盖,

B=4------> 4(B虚表指针)

C=4------> 4(C虚表指针)

5.如果子类和父类都包含虚函数,但他们存放在一个虚表中,因此只要一个虚表指针。

D=8-------->4(D虚表指针)+4(D虚表指针)

E=4--------->4(B虚表指针)

(二)、虚基类

1.什么是虚基类:

当在多条继承路径上有一个公共的基类,在这些路径中的某几条汇合处,这个公共的基类就会产生多个实例(或多个副本),若只想保存这个基类的一个实例,可以将这个公共基类说明虚基类。所以可以说,虚基类是为了只实例化一次基类存在的。

2.虚基类的特点

(1):虚基类构造函数的参数必须由最新派生出来的类负责初始化(即使不是直接继承).

(2)虚基类的构造函数先于非虚基类的构造函数执行。

3.二义性的问题

1.问题所在:

代码展示:
#include <iostream>
using namespace std;
class Student
{
public:
  int age;
 int number;
 Student(int a, int nu) :age(a), number(nu) {}
 Student() {}
  void set()
 {
  cout << "请输入学生的年龄和学号" << endl;
  cin >> age >> number;
 }
  void show()
 {
  cout << "学生的年龄为:" << " " << "学号为:" << endl;
 }
};
class Student1 :public Student
{
 void show()
 {
  cout << "Student1的" << endl; }
};
class Student2 :public Student{
 void show()
 {
  cout << "Student2的" << endl;}
};
class Student3 :public Student1,public Student2
{
 void show() {
  cout << "Student3的" << endl; }
};
int main()
{
 Student3 s3;
 s3.set();
 return 0;}
效果展示:

2.【二义性的解决非虚基类正确示范】

代码展示
#include <iostream>
using namespace std;
class Student
{
public:
 int age;
 int number;
 Student(int a, int nu) :age(a), number(nu) {}
 Student() {}
 void set(){
  cout << "请输入学生的年龄和学号" << endl;
  cin >> age >> number;}
 void show()
 {
  cout << "学生的年龄为:" << " " << "学号为:" << endl;
 }
};
class Student1 :public Student
{
public:
 void show()
 {
 cout << "Student1的" << endl;
 }
};
class Student2 :public Student
{
 void show()
 {
  cout << "Student2的" << endl; }
};
class Student3 :public Student1, public Student2
{
 void show()
 {
  cout << "Student3的" << endl; }
};
int main()
{
 Student3 s3;
 s3.Student1::set();
 return 0;
}
效果展示:

3.【二义性解决虚基类的方法正确示范】

#include <iostream>
using namespace std;
class Student
{
public:
 int age;
 int number;
 Student(int a, int nu) :age(a), number(nu) {}
 Student() {}
 void set(){
  cout << "请输入学生的年龄和学号" << endl;
  cin >> age >> number;}
 void show()
 {
  cout << "学生的年龄为:" << " " << "学号为:" << endl;
 }
};
class Student1 :virtual public Student
{
public:
 void show(){
  cout << "Student1的" << endl;}};
class Student2 :virtual public Student
{
 void show()
 {
  cout << "Student2的" << endl;}
};
class Student3 :public Student1, public Student2
{
 void show() {
  cout << "Student3的" << endl;}
};
int main()
{
 Student3 s3;
 s3.set();
 return 0;
}
代码展示

(三)、纯虚函数

1.纯虚函数的作用

在许多情况下,在基类中不能对虚函数给出有意义的实现,而把它声明为纯虚函数,它的实现留给该基类的派生类去做。这就是纯虚函数的作用。

2.基本格式:

class <类名>
{
    virtual <类型><函数名>(<参数表>)=0;…
};

(四)、总结

虚基类

1, 一个类可以在一个类族中既被用作虚基类,也被用作非虚基类。

2, 在派生类的对象中,同名的虚基类只产生一个虚基类子对象,而某个非虚基类产生各自的子对象。

3, 虚基类子对象是由最新派生类的构造函数通过调用虚基类的构造函数进行初始化的

4, 最派生类是指在继承结构中建立对象时所指定的类。

5, 派生类的构造函数的成员初始化列表中必须列出对虚基类构造函数的调用;如果未列出,则表示使用该虚基类的缺省构造函数。

6, 从虚基类直接或间接派生的派生类中的构造函数的成员初始化列表中都要列出对虚基类构造函数的调用。但只有用于建立对象的最派生 类的构造函数调用虚基类的构造函数,而该派生类的所有基类中列出的对虚基类的构造函数的调用在执行中被忽略,从而保证对虚基类子对象 只初始化一次。

7, 在一个成员初始化列表中同时出现对虚基类和非虚基类构造函数的调用时,虚基类的构造函数先于非虚基类的构造函数执行

虚函数

1, 虚函数是非静态的、非内联的成员函数,而不能是友元函数,但虚函数可以在另一个类中被声明为友元函数。

2, 虚函数声明只能出现在类定义的函数原型声明中,而不能在成员函数的函数体实现的时候声明。

3, 一个虚函数无论被公有继承多少次,它仍然保持其虚函数的特性。

4, 若类中一个成员函数被说明为虚函数,则该成员函数在派生类中可能有不同的实现。当使用该成员函数操作指针或引用所标识的对象时 ,对该成员函数调用可采用动态联编。

5, 定义了虚函数后,程序中声明的指向基类的指针就可以指向其派生类。在执行过程中,该函数可以不断改变它所指向的对象,调用不同 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。 纯虚函数 版本的成员函数,而且这些动作都是在运行时动态实现的。虚函数充分体现了面向对象程序设计的动态多态性。

纯虚函数

1, 当在基类中不能为虚函数给出一个有意义的实现时,可以将其声明为纯虚函数,其实现留待派生类完成。

2, 纯虚函数的作用是为派生类提供一个一致的接口。

3, 纯虚函数不能实列化

相关文章
|
5月前
|
C++
C++一分钟之-虚函数与抽象类
【6月更文挑战第21天】在C++中,虚函数与抽象类是多态的基础,增进类间耦合与灵活性。虚函数实现动态绑定,抽象类定义不可实例化的接口。关键点包括:记得使用`virtual`,避免滥用虚函数,确保派生类实现纯虚函数。抽象类不能直接实例化,派生类必须实现所有纯虚函数。通过实例代码学习和实践,能更好地掌握这些概念以优化代码设计。
50 2
|
6月前
|
C++
C++程序中的纯虚函数
C++程序中的纯虚函数
47 0
|
3月前
|
编译器 C++ 索引
C++虚拟成员-虚函数
C++虚拟成员-虚函数
|
4月前
|
Java 编译器 程序员
C++中的语法知识虚继承和虚基类
**C++中的多继承可能导致命名冲突和数据冗余,尤其在菱形继承中。为解决这一问题,C++引入了虚继承(virtual inheritance),确保派生类只保留虚基类的一份实例,消除二义性。虚继承通过`virtual`关键字指定,允许明确访问特定路径上的成员,如`B::m_a`或`C::m_a`。这样,即使基类在继承链中多次出现,也只有一份成员副本,简化了内存布局并避免冲突。虚继承应在需要时提前在继承声明中指定,影响到从虚基类派生的所有后代类。**
|
6月前
|
Serverless C++
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
C++多态性、虚函数、纯虚函数和抽象类知识网络构造
|
6月前
|
C++ 开发者
C++程序中利用虚函数实现动态多态性
C++程序中利用虚函数实现动态多态性
57 2
|
6月前
|
数据安全/隐私保护 C++
C++中的虚函数、纯虚函数与函数重写的技术性探讨
C++中的虚函数、纯虚函数与函数重写的技术性探讨
91 0
|
6月前
|
编译器 C++
C++的虚函数
C++的虚函数
37 0
|
6月前
|
C++
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
C++|多态性与虚函数(2)|虚析构函数|重载函数|纯虚函数|抽象类
|
8天前
|
存储 编译器 C++
【c++】类和对象(中)(构造函数、析构函数、拷贝构造、赋值重载)
本文深入探讨了C++类的默认成员函数,包括构造函数、析构函数、拷贝构造函数和赋值重载。构造函数用于对象的初始化,析构函数用于对象销毁时的资源清理,拷贝构造函数用于对象的拷贝,赋值重载用于已存在对象的赋值。文章详细介绍了每个函数的特点、使用方法及注意事项,并提供了代码示例。这些默认成员函数确保了资源的正确管理和对象状态的维护。
35 4