C++ 中抽象与封装的区别
在 C++ 中,抽象(Abstraction)和封装(Encapsulation)是两个重要的概念。虽然它们的名字听起来很相似,但它们有着不同的含义。本文将介绍它们的区别以及如何在C++中实现它们。
抽象
抽象是指从具体事物中抽离出它们共通的、核心的特征,并将其简化为一个更为通用的概念或模型。抽象过程包括从具体的实例或现象中提取出共性的、重要的特性,并基于这些特性建立一个更为抽象的概念。
在 C++ 中,抽象的体现是通过虚函数来实现的。虚函数是在基类中声明的一种特殊类型的函数,其定义在派生类中。虚函数的作用是允许派生类重新定义它并覆盖基类中的同名函数。
以下是一个用虚函数实现抽象的示例:
class Shape {
public:
virtual double getArea() = 0; // 声明一个纯虚函数
};
class Circle : public Shape {
private:
double radius;
public:
Circle(double radius) : radius(radius) {}
double getArea() { return 3.14 * radius * radius; }
};
class Square : public Shape {
private:
double edge;
public:
Square(double edge) : edge(edge) {}
double getArea() { return edge * edge; }
};
在上面的代码中,Shape 是一个基类,它声明了一个纯虚函数 getArea(),但是没有为它提供实现。这个纯虚函数纯粹是为了被派生类重载而存在的,因为不同的 Shape 子类有不同的计算面积的方式。
Circle 类和 Square 类都继承了 Shape 类,并分别实现了 getArea() 函数,以自己的方式计算出自己的面积。由于 Shape 中的 getArea() 函数是一个纯虚函数,不能被实例化,因此 Shape 类具有纯抽象的性质。
封装
封装是指把一个实现细节隐藏起来,只暴露出一些公共的接口给外部使用。封装的目的是为了保护数据和实现,同时避免外部的随意访问。在 C++ 中,封装的实现依赖于访问控制符:public、protected 和 private。
以下是一个封装数据的例子:
class Date {
private:
int day;
int month;
int year;
public:
int getDay() const { return day; }
void setDay(int day) { this->day = day; }
int getMonth() const { return month; }
void setMonth(int month) { this->month = month; }
int getYear() const { return year; }
void setYear(int year) { this->year = year; }
};
在上面的代码中,我们定义了一个名为 Date 的类。这个类有三个私有变量 day、month 和 year,以及三个公共接口函数 getDay()、setDay()、getMonth()、setMonth()、getYear() 和 setYear()。这些公共接口的作用是通过对数据成员的访问和修改,为外部代码提供对 Date 类的访问。
尽管这里仍然是允许外部代码访问类的私有成员,但是这种访问是受到限制的,而且只能通过类的公共接口来完成。
结论
在 C++ 中,抽象和封装是两个重要的概念,它们的目的都是为了提高代码的可读性和可维护性。抽象是将具体的事物转换为一些更为通用的概念,从而减少代码冗余和维护成本。而封装是将实现细节隐藏起来,只暴露出一些公共的接口给外部使用,从而保护数据和实现,并且避免外部的随意访问。熟练掌握抽象和封装的原理和实现方法,在写出高效、安全、易维护的 C++ 代码方面至关重要。