带你从头学习C++的封装攻略
为什么要学习C++的封装?
C++是一门重要的编程语言,其独有的面向对象编程(Object-oriented programming, OOP)特性使得其在编程领域得到广泛应用。其中,封装是OOP最基本的特性之一,意味着将类的实现细节隐藏在外部接口后面,并且通过公共的方法使数据受到限制和保护。通过使用封装,我们可以更好地组织我们的代码、提高代码重用性、增强代码可读性及可维护性,减少对其他代码的影响等等。
因此,了解和掌握C++的封装是成为一名优秀的C++程序员的必备技能。
C++的封装攻略
1. 定义类
首先,我们需要定义一个类,这个类通常包含数据成员和成员函数。其中,数据成员是我们需要隐藏的数据,而成员函数则是我们能够对这些数据进行操作的方法。以下是一个例子:
class Rectangle {
private:
double length;
double width;
public:
void setLength(double len);
void setWidth(double wid);
double getLength() const;
double getWidth() const;
double getArea() const;
};
在这个例子中,我们定义了一个名为Rectangle的类,其中包含了两个私有的double型数据成员length和width,以及四个公共的成员函数setLength、setWidth、getLength和getWidth,以及一个返回矩形面积的成员函数getArea。
2. 实现类
接下来,我们需要实现这个类。实现封装的主要方法是使用访问控制符:private、public和protected。在我们的例子中,我们把length和width设置为private,以便外界不能够直接访问它们,而成员函数则设置为public,这样,外界可以通过成员函数来访问和修改length和width的值。
在实现类的过程中,我们需要注意以下几点:
- 数据成员要设置为private
- 成员函数要设置为public,并且最好设置为const(不修改类的任何数据成员)
- 不要允许为成员函数添加参数来修改数据成员的值
下面是Rectangle类的实现部分:
void Rectangle::setLength(double len) {
length = len;
}
void Rectangle::setWidth(double wid) {
width = wid;
}
double Rectangle::getLength() const {
return length;
}
double Rectangle::getWidth() const {
return width;
}
double Rectangle::getArea() const {
return length * width;
}
3. 使用类
最后,我们需要使用我们定义和实现的类。这包括创建对象、设置数据成员的值以及尝试访问和修改数据成员的值。在我们的例子中,我们可以这样使用Rectangle类:
Rectangle rectangle;
rectangle.setLength(5.0);
rectangle.setWidth(3.0);
double area = rectangle.getArea();
在这个例子中,我们创建了一个rectangle对象,并分别设置其length和width的值为5.0和3.0,然后通过getArea函数计算并返回其面积。
示例说明
示例1:银行账户
假设我们需要定义一个银行账户类,该类具有以下特征:
- 每个账户都有一个唯一的账号和属于该账户的余额。
- 账号是只读的,不能更改。
- 可以使用存款和提款函数修改余额。
我们来定义一个BankAccount类来实现这个功能,代码如下:
class BankAccount {
private:
long accountNumber;
double balance;
public:
BankAccount(long accountNumber, double initialBalance);
void deposit(double amount);
bool withdraw(double amount);
double getBalance() const;
long getAccountNumber() const;
};
在我们的类定义中,BankAccount类包含了一个私有的long型数据成员accountNumber和一个私有的double型数据成员balance,以及三个公共的成员函数:BankAccount构造函数、进行存款的deposit函数和进行提款的withdraw函数,以及一个返回账户余额的getBalance函数和一个返回账户号码的getAccountNumber函数。
实现部分如下:
BankAccount::BankAccount(long accountNumber, double initialBalance) : accountNumber(accountNumber), balance(initialBalance) {}
void BankAccount::deposit(double amount) {
balance += amount;
}
bool BankAccount::withdraw(double amount) {
if (amount > balance) {
std::cout << "Error! Not enough money!" << std::endl;
return false;
}
balance -= amount;
return true;
}
double BankAccount::getBalance() const {
return balance;
}
long BankAccount::getAccountNumber() const {
return accountNumber;
}
在这个实现过程中,我们引入了一个构造函数,用于初始化银行账户对象的accountNumber和balance属性。deposit函数和withdraw函数用于存款和提款,getBalance函数和getAccountNumber函数用于返回银行账户余额和账户号码。
最后,我们使用以下代码来使用BankAccount类:
BankAccount account(12345678, 1000.0);
std::cout << "Initial balance: " << account.getBalance() << std::endl;
account.deposit(500.0);
std::cout << "After deposit: " << account.getBalance() << std::endl;
account.withdraw(200.0);
std::cout << "After withdrawal: " << account.getBalance() << std::endl;
在这个例子中,我们创建了一个名为account的BankAccount对象,并使用构造函数初始化它的accountNumber和balance属性。然后,我们使用deposit函数存入500.0美元,再次使用withdraw函数提取200.0美元,并使用getBalance函数两次输出当前余额。
示例2:动态分配内存
下面以动态分配内存为例,说明C++中封装思想强化了内存安全和使用效率。我们先考虑没有封装带来的危险:
int main()
{
int* p = new int[10];
int* q = p;
*p = 5;
*(p + 1) = 10;
std::cout << *q << std::endl;
delete[] p;
return 0;
}
我们在堆上动态分配10个int型空间,但是不加任何保护地访问了其中前两个元素,然后要通过delete[]删除指向堆空间的指针p,这样就有误操作导致了堆栈的混乱。
通过封装思想的成员函数,可以消除这种危险,例如:
class MyArray{
int *m_Data;
int m_Length;
public:
MyArray(int length)
{
m_Length = length;
m_Data = new int[length];
}
~MyArray()
{
delete[] m_Data;
}
void setValue(int index, int value)
{
if(index < 0 || index >= m_Length)
throw "Invalid index!";
m_Data[index] = value;
}
int getValue(int index) const
{
if(index < 0 || index >= m_Length)
throw "Invalid index!";
return m_Data[index];
}
};
int main()
{
MyArray array(10);
array.setValue(0, 5);
array.setValue(1, 10);
std::cout << array.getValue(0) << std::endl;
return 0;
}
由上可知,通过封装,我们可以规定MyArray中的成员变量m_Data只能用setValue和getValue函数来访问,同时还加入了判越界的保护。如此一来,不管是谁使用MyArray,都不能像在第一个例子中那样拿指针乱指,也就增加了程序的健壮性和可维护性。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:带你从头学习C++的封装 - Python技术站