C++基础_类的基本理解
文章目录
- 1. 类的基本理解
- 2. 组织代码并管理复杂性
- 2.1 封装
- 用类来封装数据和行为
- 使用private封装数据
- 2.2 减少重复代码,增强复用性
- 2.3 提升代码的可扩展性 —— 继承与派生
- 2.4 增强代码的逻辑性和可读性
- 2.5 支持设计模式
- 单例模式的应用
- 3. 完整示例代码
本文暂不涉及关于类的语法规则,以介绍思路和为什么为主,并没有很详细地呈现C++语言规则本身相关内容,因此从语法角度来讲,示例中可能存在不合适的地方,但不影响整体的理解。
1. 类的基本理解
类是C++核心的编程方式。将数据以及操作这些数据的函数封装在一起,使得数据(“成员变量”)和函数(“成员方法”)都成为类的内部成员。这种封装机制能够让代码更加干净,更好地被理解和维护。
当程序规模增大、代码复杂性增加时,类的设计和使用尤为重要,能够让代码的组织结构更加清晰、逻辑更加集中,且能够管理复杂性。同时,也能够提高代码的复用性和扩展性。
每个类的对象,即类的“实例”,都会有自己的成员变量和成员方法。意味着每个对象可以拥有独立的状态和行为,保持模块化。
因此,可以简单理解为,类允许我们将相关的变量和功能打包到一个类型中,将数据和操作逻辑紧密结合起来,形成一个更具组织性、层次性的结构。
类并不会提供新的功能,可以简单总结:
用类可以搞定的事情,不用类一定也行的
但是如果用类搞不定的事情,不用类是肯定搞不定的
理论上所有用“类”可以实现的功能,都可以通过非面向对象的方式实现,所以C语言依然可用,但是类带来的优势却是非面向对象的方式难以替代的。
2. 组织代码并管理复杂性
2.1 封装
用类来封装数据和行为
假设一开始我们用全局变量来表示商品和客户信息,例如:
string productName;
double productPrice;
int productQuantity;
很快我们就会发现,管理多个商品时需要更多的变量,比如 productName1、productName2等。这样以来,变量数量增加,代码会变得混乱。
用类封装后,可以定义一个Product
类,把商品的信息都封装在一起,这样,我们就可以通过创建多个Product对象来管理多个商品,而不用为每个商品创建单独的变量,代码结构更加清晰:
class Product
{
public:
string m_name;
double m_price;
int m_quantity;
};
每个Product都有自己的信息,可以避免一堆散乱的无组织的变量,从而引发混乱
int main()
{
Product apple;
apple.m_name = "Apple";
apple.m_price = 2.5;
apple.m_quantity = 100;
Product banana;
banana.m_name = "Banana";
banana.m_price = 1.5;
banana.m_quantity = 150;
return 0;
}
使用private封装数据
通过访问控制符(privare、protected和public)控制对类内部成员的访问,增强封装效果。
- public 公有成员,类外部可以直接访问
- private 私有成员,仅类的内部可以直接访问,类的外部不可直接访问
- protected 受保护成员,仅类的内部和子类可以访问
通过这种方式,类提供对外的公共接口public方法,隐藏内部的private数据。
外部只能通过public方法(接口)来访问和操作类的私有数据成员。这样外部访问数据通过你给定的方式来访问数据,就变得可控,避免了不正确的操作对数据的不合理的更改,保障了数据安全性和一致性。
同时,封装隐藏了数据的具体情况,使得外部使用数据不依赖于内部数据的具体结构和存储方式,即便我们在类的内部修改了数据存储结构等细节,也不影响外部的调用。
2.2 减少重复代码,增强复用性
随着功能增加,假设我们还要显示商品详情。可以在 Product 类中增加一个方法来显示商品信息,这样不必在每个地方重复写代码。
void displayInfo()
{
cout << "Product: " << m_name << " , Price: " << m_price << " , Quantity: " << m_quantity << endl;
}
简单地调用
apple.displayInfo() 来显示苹果的详细信息,banana.displayInfo()来显示香蕉的详细信息。
apple.displayInfo();
banana.displayInfo();
2.3 提升代码的可扩展性 —— 继承与派生
假设我们的商店增加了一个新的需求:销售打折商品。
那么我们可以在不修改 Product 类的情况下,通过继承来扩展功能
创建一个 DiscountProduct 类,继承自 Product:
class DiscountProduct : public Product
{
public:
double m_discountRate; // 按生活中通常的计算方式:打 7 折 * 0.7 不是 * 0.3
double getDiscountPrice()
{
return m_price * m_discountRate;
}
void displayInfo()
{
cout << "Product: " << m_name << " , Original Price: " << m_price
<< " , Discounted Price: " << getDiscountPrice()
<< " , Quantity: " << m_quantity << endl;
}
};
虽然 DiscountProduct
和 Product
都表示商品,但折扣商品需要额外的属性和行为(折扣率和折后价格计算),这里就是通过“继承”来复用 Product
类的已有代码,并在 DiscountProduct
类中扩展新的功能。
通过这种设计,避免了在 Product
类中增加和普通商品无关的内容(如折扣率),让Product
保持简单,同时通过DiscountProduct
来专门处理打折商品的逻辑
在DiscountProduct
类中,我们添加了一个新的成员变量折扣率,重写了displayInfo
方法
2.4 增强代码的逻辑性和可读性
随着系统的复杂度增加,各种各样的数据会变得难以管理,假设我们没有类,而是直接用数组或全局变量记录商品、客户和订单信息,代码会变得难以阅读和理解。
但是如果用类来组织逻辑,就可以把相关的逻辑封装在各自的类里,比如 Customer 类 和 Order 类。
class Order
{
public:
int m_orderID;
vector<Product> m_products;
Order(int id) :m_orderID(id) {}
void addProduct(const Product& product)
{ m_products.push_back(product);
}
double calculateTotalAmount()
{
double total = 0.0;
for (const auto& product : m_products)
{
total += product.m_price * product.m_quantity;
}
return total;
}
void dispalyOrderInfo()
{
cout << "Order ID: " << m_orderID << endl;
for (auto& product : m_products)
{
product.displayInfo();
}
cout << "Total Amount: " << calculateTotalAmount() << endl;
}
};
class Customer
{
public:
string m_name;
string m_address;
vector<Order> m_orders;
void addOrder(Order order)
{
m_orders.push_back(order);
}
};
这样将客户的信息和订单集中在 Customer 类里,便于阅读和维护。同时,修改或者查找某个信息时,只要在对应的类中寻找即可,逻辑更加集中。
2.5 支持设计模式
还以上面的场景为例,假设我们要添加一个库存管理系统,用于跟踪没中商品的库存数量,以便商品在被添加到订单时更新库存,在库存不足时禁止下单。这正是单例模式非常典型的应用场景,在在大型项目中非常有用
单例模式的应用
在一个复杂的系统中,类似库存、日志、配置等全局资源通常需要集中管理。
想象一下,假如在购物系统中,库存管理存在多个实例,那么不同部分访问不同的实例,就会导致库存数据的不一致。
因此,必须提供一个全局访问点,系统中的任何模块(例如 customer order等),都只能通过系统中唯一一个库存管理实例来更新库存,这样才能安全、统一地访问库存数据,从而管理商品库存,避免多个库存数据副本带来库存数据的混乱,保证数据的一致性。
3. 完整示例代码
主要包括类的创建(例如Product
类和DiscountProduct
类)、继承与多态(例如DiscountProduct
继承自Product
并重写了displayInfo()
方法)、单例模式(例如InventoryManager
只有一个实例存在,避免数据不一致)、类的组合(例如Order
包含Product
列表,Customer
包含Order
列表)
每个类都围绕不同的职责进行了划分,使得代码结构清晰,易于扩展和维护
#include<iostream>
#include<string>
#include<vector>
#include<unordered_map>
using namespace std;
class Product
{
public:
string m_name;
double m_price;
int m_quantity;
Product(string name, double price, int quantity)
:m_name(name), m_price(price), m_quantity(quantity) {}
void displayInfo() const
{
cout << "Product: " << m_name << " , Price: " << m_price
<< " , Quantity: " << m_quantity << endl;
}
};
class DiscountProduct : public Product
{
public:
double m_discountRate; // 按生活中通常计算方式:打 7 折 * 0.7 不是 * 0.3
DiscountProduct(string name, double price, int quantity, double discountRate)
:Product(name, price, quantity), m_discountRate(discountRate) {}
double getDiscountPrice()
{
return m_price * m_discountRate;
}
void displayInfo()
{
cout << "Product: " << m_name << " , Original Price: " << m_price
<< " , Discounted Price: " << getDiscountPrice()
<< " , Quantity: " << m_quantity << endl;
}
};
class InventoryManager
{
private:
static InventoryManager* instance;
unordered_map<string, int> stock; // 跟踪每个商品库存
// 私有构造函数,防止外部直接创建实例
InventoryManager() {}
public:
// 禁用复制构造函数和赋值操作
InventoryManager(const InventoryManager&) = delete;
InventoryManager& operator=(const InventoryManager&) = delete;
// 获取单例实例
static InventoryManager* getInstance()
{
if (instance == nullptr)
instance = new InventoryManager();
return instance;
}
// 增加库存
void addStock(const string& productName, int quantity)
{
stock[productName] += quantity;
cout << "Added " << quantity << " units of " << productName << " to the inventory. " << endl;
}
// 检查库存
bool isInStock(const string& productName, int quantity)
{
return stock[productName] >= quantity;
}
// 减少库存
void reduceStock(const string& productName, int quantity)
{
if (isInStock(productName, quantity))
{
stock[productName] -= quantity;
cout<<"Reduced "<<quantity<<" units of "<<productName<<" from the inventory. " << endl;
}
else
{
cout << "Insufficient stock for " << productName << " ! " << endl;
}
}
// 显示库存信息
void dispalyStock() const
{
cout << "Current Inventory: " << endl;
for (const auto& item : stock)
{
cout << "Product: " << item.first << " , Quantity: " << item.second << endl;
}
}
};
// 初始化静态成员
InventoryManager* InventoryManager::instance = nullptr;
class Order
{
public:
int m_orderID;
vector<Product> m_products;
Order(int id) :m_orderID(id) {}
void addProduct(const Product& product)
{
InventoryManager* inventory = InventoryManager::getInstance();
// 检查库存,确保可以添加到订单里
if (inventory->isInStock(product.m_name, product.m_quantity))
{
m_products.push_back(product);
inventory->reduceStock(product.m_name, product.m_quantity); // 更新库存
}
else
{
cout << "Product " << product.m_name << " is out of stock!" << endl;
}
}
double calculateTotalAmount() const
{
double total = 0.0;
for (const auto& product : m_products)
{
total += product.m_price * product.m_quantity;
}
return total;
}
void displayOrderInfo() const
{
cout << "Order ID: " << m_orderID << endl;
for (auto& product : m_products)
{
product.displayInfo();
}
cout << "Total Amount: " << calculateTotalAmount() << endl;
}
};
class Customer
{
public:
string m_name;
string m_address;
vector<Order> m_orders;
void addOrder(Order order)
{
m_orders.push_back(order);
}
};
int main()
{
InventoryManager* inventory = InventoryManager::getInstance();
// 增加库存
inventory->addStock("Laptop", 10);
inventory->addStock("Headphones", 20);
// 创建产品
Product laptop("Laptop", 1000.0, 1);
DiscountProduct headphones("Headphones", 100.0, 2, 0.8);
// 创建订单
Order order(101);
order.addProduct(laptop);
order.addProduct(headphones);
// 显示订单信息
order.displayOrderInfo();
// 显示库存信息
inventory->dispalyStock();
return 0;
}