封装是许多编程语言中的一个关键概念。虽然它主要用于面向对象编程(oop)语言,但也是许多其他语言的特性。在使用对象时,我们经常希望将内部工作隐藏在外部类之外。这有助于限制其修改并使其在长期内更加健壮和安全。c++中封装的工作方式与python等其他语言不同。在本文中,我们将详细介绍c++中封装的工作原理以及实现封装的方法。
c++中的封装是什么以及为什么使用它?
封装通常指的是将代码封装成一个单元,从外部类中对内部工作的访问进行限制。您可以将其视为组织内部的机密文件夹,这些文件夹受到保护。只有组织中的某些成员才能访问所有信息,并且通常会根据谁需要访问哪个部分的详细信息进行层次化访问。封装的工作原理与此类似。这导致了更友好的用户界面,数据保护以及更安全的代码。
c++中的封装如何实施?
c++的封装与其他语言有所不同。python没有内置的访问修饰符,而c++具有用于调整代码可见性的访问说明符。这些包括public、private和protected。正如您可能期望的那样,public成员可以从类内部和外部的任何地方访问。但是,private成员只能从同一类内部访问。protected成员可以从类内部访问,也可以从任何派生类访问。
我们还可以在c++中使用友元函数,这些函数可以在类外部访问私有和受保护的成员。这可以提供对代码的灵活使用,但从技术上讲会破坏封装。因此,如果可能的话,通常应避免使用友元函数,并且仅在绝对必要时使用。
c++中封装的示例
有许多情况下封装是可取的。首先,让我们考虑以下示例:
#include <iostream>
using namespace std;
class circle {
private:
double radius;
public:
void setradius(double r) {
if (r > 0)
radius = r;
else
cout << "invalid radius!" << endl;
}
double getradius() {
return radius;
}
double calculatearea() {
return 3.14 * radius * radius;
}
};
int main() {
circle mycircle;
mycircle.setradius(5.0);
cout << "radius: " << mycircle.getradius() << endl;
cout << "area: " << mycircle.calculatearea() << endl;
return 0;
}
在这里,我们定义了私有的”circle”类,其中有私有成员变量”radius”。这只能从类内部访问。该类还有3个公共成员函数 – “setradius”,”getradius”和”calculatearea”。
如果输入的”r”为负数,则”setradius”将报告错误消息。因此,我们控制对此函数的访问,以确保输入无效。因此,”radius”变量被封装起来,其实现对外部类隐藏。
在这个例子中,我们提供了一个半径为5.0的值,该值由”getradius”获取,并由”calculatearea”用于计算圆的面积。输出结果可以在下面的图像中看到。
通过一个例子来说明c++中的封装。
©jingzhengli.com
使用受保护成员的c++封装
前面的例子使用了私有成员来实现封装。然而,也可以使用受保护成员来实现。例如,考虑下面的代码:
#include <iostream>
using namespace std;
class circle {
protected:
double radius;
public:
void setradius(double r) {
if (r > 0)
radius = r;
else
cout << "无效的半径!" < 0)
height = h;
else
cout << "无效的高度!" << endl;
}
double getheight() {
return height;
}
double calculatevolume() {
return calculatearea() * height;
}
};
int main() {
cylinder mycylinder;
mycylinder.setradius(3.0);
mycylinder.setheight(5.0);
cout << "半径:" << mycylinder.getradius() << endl;
cout << "高度:" << mycylinder.getheight() << endl;
cout << "面积:" << mycylinder.calculatearea() << endl;
cout << "体积:" << mycylinder.calculatevolume() << endl;
return 0;
}
这段代码使用了类似的例子,但进行了一些修改。首先,我们有了额外的”cylinder”类,它派生自”circle”。因此,”cylinder”继承了”circle”的函数。由于这个类是protected而不是private,我们可以在派生类中使用这些函数。我们创建了一个名为”mycylinder”的”cylinder”的实例,设置了半径和高度,然后计算了面积和体积。这仍然提供了一定程度的封装,但比私有成员更灵活。
使用受保护成员的封装示例。
©jingzhengli.com
非封装示例
为了展示封装和非封装代码之间的差异,我们可以修改第一个例子,使其不再封装。可以描述如下:
#include <iostream>
using namespace std;
double setradius(double r) {
if (r > 0)
return r;
else {
cout << "无效的半径!" << endl;
return 0.0;
}
}
double getradius(double radius) {
return radius;
}
double calculatearea(double radius) {
return 3.14 * radius * radius;
}
int main() {
double myradius = setradius(5.0);
double myarea = calculatearea(myradius);
cout << "半径:" << myradius << endl;
cout << "面积:" << myarea << endl;
return 0;
}
我们在这里删除了“circle”类,并用非成员函数替换了成员函数。因此,函数不再访问成员变量,而是将参数作为参数。我们仍然检查半径值的有效性。”setradius”函数将半径值存储在”myradius”中,并将其传递给”calculatearea”以返回圆的面积。总体而言,这意味着可以从类外部直接访问值。如图所示,结果是相同的,但是在c++中封装允许代码更好地组织和重用。
第一个示例程序已经修改为在没有封装的情况下工作。
©jingzhengli.com
总结
封装是所有程序员,特别是使用面向对象编程语言的程序员都需要了解的关键概念。尽管可以使用局部变量实现类似的功能,但封装更可取。这是因为它有助于使代码更加强大,免受外部影响和意外修改的影响,并且通常会导致更简化和有组织的代码。c++使用访问说明符来强制封装,但在适当的情况下可以使用友元函数来减轻这种限制。