实现一个合格的自定义类
Effective C++ 条款19中指明了合格自定义类应该包含的设计规范,以下是一些关键的思考点和设计考虑,以帮助设计一个新的自定义类:
- 对象的创建和销毁:
- 构造函数应该负责对象的初始化,可以有多个构造函数以支持不同的初始化方式。
- 析构函数用于释放对象所占用的资源,如动态分配的内存等。
- 对象的初始化和赋值的差异:
- 初始化是在对象创建时进行的,构造函数负责初始化对象的状态。
- 赋值是将一个对象的值复制给另一个对象,赋值操作符重载函数负责定义对象的赋值行为。
- 值传递的影响:
- 如果对象被按值传递,会调用拷贝构造函数来创建传递的副本。
- 合法值和约束条件:
- 对于类的成员变量,应该定义它们的合法取值范围,以及确保对象的不变量。
- 构造函数、赋值操作符和setter函数应该进行错误检查,确保输入的值符合约束条件。
- 继承关系:
- 如果你的类需要作为基类,需要考虑是否需要将析构函数声明为虚函数,以支持多态性。
- 如果允许其他类继承你的类,需要考虑基类的设计对派生类的影响,特别是虚函数的处理。
- 类型转换:
- 根据需要,可以定义类型转换函数或构造函数,以支持对象与其他类型的转换。
- 合理的操作符和函数:
- 根据类的功能和需求,声明适当的成员函数和操作符重载函数。
- 标准函数的声明:
- 根据需要,将一些函数声明为私有成员,以控制外部访问。
- 成员的访问控制:
- 决定哪些成员应该是公有、保护或私有的,以及是否需要友元类或函数。
- 未声明接口:
- 考虑效率、异常安全性以及资源管理方面的保证,以确保类的实现符合预期的约束条件。
- 泛化:
- 如果你要定义一整个类型家族,可能需要考虑使用类模板而不是单独的类来实现。
在设计新的自定义类时,仔细考虑以上问题,可以帮助你建立一个合理、健壮和易于使用的类。
提供一个简单的C++类的例子,以演示如何根据前述的设计考虑实现一个自定义类。这个例子是一个表示有理数(Rational Number)的类,包含构造函数、析构函数、拷贝构造函数、加法、减法、乘法、除法操作符重载,以及显式和隐式转换。
cpp
#include <iostream>
class Rational {
private:
int numerator;
int denominator;
public:
// 构造函数
Rational(int num = 0, int denom = 1) : numerator(num), denominator(denom) {
if (denominator == 0) {
std::cerr << "Error: Denominator cannot be zero." << std::endl;
// 处理错误情况,可以设置默认值或抛出异常
numerator = 0;
denominator = 1;
}
}
// 拷贝构造函数
Rational(const Rational& other) : numerator(other.numerator), denominator(other.denominator) {}
// 析构函数
~Rational() {
// 可以在这里执行清理工作
}
// 加法操作符重载
Rational operator+(const Rational& other) const {
int resultNumerator = numerator * other.denominator + other.numerator * denominator;
int resultDenominator = denominator * other.denominator;
return Rational(resultNumerator, resultDenominator);
}
// 减法操作符重载
Rational operator-(const Rational& other) const {
int resultNumerator = numerator * other.denominator - other.numerator * denominator;
int resultDenominator = denominator * other.denominator;
return Rational(resultNumerator, resultDenominator);
}
// 乘法操作符重载
Rational operator*(const Rational& other) const {
int resultNumerator = numerator * other.numerator;
int resultDenominator = denominator * other.denominator;
return Rational(resultNumerator, resultDenominator);
}
// 除法操作符重载
Rational operator/(const Rational& other) const {
// 避免除零错误
if (other.numerator != 0) {
int resultNumerator = numerator * other.denominator;
int resultDenominator = denominator * other.numerator;
return Rational(resultNumerator, resultDenominator);
} else {
std::cerr << "Error: Division by zero." << std::endl;
return Rational(); // 返回一个默认值或抛出异常
}
}
// 显式转换为double类型
explicit operator double() const {
return static_cast<double>(numerator) / static_cast<double>(denominator);
}
// 输出有理数
friend std::ostream& operator<<(std::ostream& os, const Rational& rational) {
os << rational.numerator << "/" << rational.denominator;
return os;
}
};
int main() {
Rational num1(1, 2);
Rational num2(3, 4);
Rational sum = num1 + num2;
Rational difference = num1 - num2;
Rational product = num1 * num2;
Rational quotient = num1 / num2;
std::cout << "Sum: " << sum << std::endl;
std::cout << "Difference: " << difference << std::endl;
std::cout << "Product: " << product << std::endl;
std::cout << "Quotient: " << quotient << std::endl;
double result = static_cast<double>(num1); // 显式转换为double
std::cout << "Double Value: " << result << std::endl;
return 0;
}