【C++】虚函数、纯虚函数、虚基类

文章介绍了C++中实现动态多态性的关键机制——虚函数,包括如何声明和使用虚函数,以及虚函数的作用。接着讨论了纯虚函数和抽象类的概念,指出它们在接口定义中的重要性。最后,文章阐述了虚基类在解决多继承中数据冗余和二义性问题的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【虚函数】

为了解决动态多态性(动态联编)的问题

例:

#include<iostream>
using namespace std;
const double PI=3.14;
class Point
{
private:
	int x,y;
public:
	Point(int a,int b)
	{
		x=a,y=b;
	}
	virtual double area()//虚函数
	{
		return 0;
	}
};
class Circle:public Point
{
private:
	int r;
public:
	Circle(int a,int b,int rr):Point(a,b)
	{
		r=rr;
	}
	double area()
	{
		return PI*r*r;
	}
};
int main()
{
	Point obj(10,10);//调用point的area()函数
	cout<<"obj.area()="<<obj.area()<<endl;
	Circle obj2(10,10,4);//调用circle的area()函数
	cout<<"obj2.area()="<<obj2.area()<<endl;
	Point *C=&obj2;//调用circle的area()函数
				   //使用了指针
	cout<<"C->area()="<<C->area()<<endl;
	Point &D=obj2;//调用circle的area()函数
				  //使用引用
	cout<<"D.area()="<<D.area()<<endl;
	system("pause");
	return 0;
}

 

提示:(1)虚函数不能是静态成员函数也不能是友元函数

(2)构造函数不能是虚函数,析构函数可以为虚函数

(3)调用虚函数时,只有通过指向基类的指针或引用,才能体现虚函数与一般函数的区别

【纯虚函数】

#include<iostream>
using namespace std;
const double PI=3.14;
class Shape
{
public:
	virtual double area()=0;//纯虚函数
};
class Point:public Shape
{
private:
	int x,y;
public:
	Point(int a,int b)
	{
		x=a,y=b;
	}
	double area()
	{
		return 0;
	}
};
class Circle:public Point
{
private:
	int r;
public:
	Circle(int a,int b,int rr):Point(a,b)
	{
		r=rr;
	}
	double area()
	{
		return PI*r*r;
	}
};
int main()
{
	Point obj(10,10);//调用point的area()函数
	cout<<"obj.area()="<<obj.area()<<endl;
	Circle obj2(10,10,4);//调用circle的area()函数
	cout<<"obj2.area()="<<obj2.area()<<endl;
	Point *C=&obj2;//调用circle的area()函数
				   //使用了指针
	cout<<"C->area()="<<C->area()<<endl;
	Point &D=obj2;//调用circle的area()函数
				  //使用引用
	cout<<"D.area()="<<D.area()<<endl;
	system("pause");
	return 0;
}

提示:(1) 带有纯虚函数的类被称为抽象类,无法实例化对象,只有被继承并重写其虚函数后才可使用,所以抽象类不能定义对象,直接定义对象指针或引用

(2)当多重继承时,基类为纯虚函数,构造函数无需一直加到基类,但如基类为普通类,构造函数需一直加

【虚基类】

解决从不同途径继承来的同名数据成员在内存中有不同的副本造成的数据不一致问题,将共同基类设计为虚基类,不仅解决二义性的问题,还节省内存

例:

假设要管理下述几类人员的如下一些数据。

teacher(教师)类:姓名、性别、年龄、职称、担任  课程; 

student(学生)类:姓名、性别、年龄、学号、系别;

#include<iostream>
#include<string>
using namespace std;
class Point
{
private:
	string name;
	char sex;
	int age;
public:
	Point(string namex,char sexx,int agex)
	{
		name=namex,sex=sexx,age=agex;
	}
	virtual void show()
	{
		cout<<"name="<<name<<endl;
		cout<<"sex="<<sex<<endl;
		cout<<"age="<<age<<endl;
	}
};
class Teacher:virtual public Point//虚基类
{
private:
	string title;
	string course;
public:
	Teacher(string namex,char sexx,int agex,string titlex,string coursex):Point(namex,sexx,agex)
	{
		title=titlex,course=coursex;
	}
	void show()
	{
		Point::show();
		cout<<"title="<<title<<endl;
		cout<<"course="<<course<<endl;
	}
};
class Student:virtual public Point//虚基类
{
private:
	int num;
	string department;
public:
	Student(string namex,char sexx,int agex,int numx,string departmentx):Point(namex,sexx,agex)
	{
		num=numx,department=departmentx;
	}
	void show()
	{
		Point::show();
		cout<<"num="<<num<<endl;
		cout<<"department="<<department<<endl;
	}
};
int main()
{
	Teacher a("chen",'x',34,"hj","gj");
	Student b("tian",'y',78,89,"dfg");
	Point *d=&a;
	d->show();
	Point *f=&b;
	f->show();
	system("pause");
	return 0;
}

提示第二个性别我设置的类型为char,所以在定义对象赋值时,用单引号表单个字符,而不是双引号,也不可以写汉字,因为一个汉字字符包含两个字符

 

### 虚函数纯虚函数的概念 在C++中,虚函数允许派生类重写基类中的成员函数行为。定义虚函数的关键字是`virtual`。当一个类中含有至少一个虚函数时,通常建议将析构函数也声明为虚函数[^2]。 ```cpp class Base { public: virtual void show() { std::cout << "Base class\n"; } }; ``` 对于纯虚函数而言,其不仅是一个虚函数,而且没有具体的实现,在基类中仅作为接口存在。含有纯虚函数的类被称为抽象类,无法直接实例化对象。这种设计模式使得基类可以规定某些方法的存在而不必提供具体实现细节,留给子类去完成这些功能的具体编码工作[^1]。 ```cpp class InterfaceExample { public: virtual void requiredMethod() = 0; // 纯虚函数 }; // 尝试创建InterfaceExample的对象将会导致编译错误 // InterfaceExample obj; ``` ### 使用场景展示 考虑如下情况: - 派生自 `Shape` 类的不同图形(如 Circle 和 Rectangle),各自实现了自己的绘制逻辑; 这样做的好处在于可以通过统一的方式处理不同类型的形状,即多态性。下面给出一段简单的代码片段来说明这一点: ```cpp #include <iostream> using namespace std; class Shape { public: virtual void draw() const = 0; // 纯虚函数 virtual ~Shape() {} // 虚析构函数 }; class Circle : public Shape { public: void draw() const override { cout << "Drawing circle...\n"; } }; class Rectangle : public Shape { public: void draw() const override { cout << "Drawing rectangle...\n"; } }; void display(Shape& s) { s.draw(); } int main() { Circle c; Rectangle r; display(c); display(r); return 0; } ``` 在这个例子中,`display` 函数接受任何继承自 `Shape` 的对象并调用它们各自的 `draw()` 方法。由于 `draw()` 是一个纯虚函数,所以每个派生类都必须提供自己版本的方法实现。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值