有理数类 Rational,重载 operator*。成员函数版本:
class Rational {
public:
const Rational operator*(const Rational& rhs) const;
};
Rational oneHalf(1,2);
Rational result = oneHalf * 2; // OK: oneHalf.operator*(2)
Rational result2 = 2 * oneHalf; // Error: 2.operator*(oneHalf) 不存在
编译器尝试 operator*(2, oneHalf) 也失败,因无匹配非成员函数。
// 非成员非友元函数(优先)
const Rational operator*(const Rational& lhs, const Rational& rhs) {
return Rational(lhs.numerator() * rhs.numerator(),
lhs.denominator() * rhs.denominator());
}
// 若需访问 private 成员,声明为 friend
class Rational {
friend const Rational operator*(const Rational&, const Rational&);
// ...
};
pImpl 惯用法下,默认 swap 需拷贝整个实现对象,效率低且可能抛异常。
class Widget {
WidgetImpl* pImpl;
public:
void swap(Widget& other) noexcept { // 1. 成员 swap
using std::swap;
swap(pImpl, other.pImpl);
}
};
namespace WidgetStuff {
template<typename T>
void swap(Widget<T>& a, Widget<T>& b) { // 2. 非成员 swap
a.swap(b);
}
}
namespace std {
template<> // 3. 全特化(仅限类)
void swap<Widget>(Widget& a, Widget& b) {
a.swap(b);
}
}
// 4. 使用示范
void foo(Widget& a, Widget& b) {
using std::swap;
swap(a, b); // 依次查找:同名空间 → 全局 → std::swap 特化 → std::swap 通用
}
// 改进前:encrypted 可能未用就析构
string encryptPassword(const string& password) {
string encrypted;
if (password.length() < MinLen) throw logic_error("too short");
// ...
return encrypted;
}
// 改进后:仅在需要时构造
string encryptPassword(const string& password) {
if (password.length() < MinLen) throw logic_error("too short");
string encrypted(password); // 直接初始化
// ...
return encrypted;
}
// 方式 A:循环外定义 + 赋值
Widget w;
for (int i=0; i<n; ++i) { w = makeWidget(i); ... }
// 1构造 + 1析构 + n赋值
// 方式 B:循环内定义
for (int i=0; i<n; ++i) { Widget w(makeWidget(i)); ... }
// n构造 + n析构
// 选择:赋值成本 < 构造+析构 选 A,否则选 B(可读性优先)
| 操作符 | 用途 | 特点 |
|---|---|---|
const_cast | 移除 const/volatile | 唯一能做此事 |
dynamic_cast | 安全向下转型 | 运行期开销大,RTTI |
reinterpret_cast | 低级位模式重解释 | 不可移植,极少用 |
static_cast | 隐式转换强制化 | 无运行期开销 |
// 反面教材:dynamic_cast 连串
for (auto p : winPtrs) {
if (auto psw = dynamic_cast<SpecialWindow*>(p.get())) psw->blink();
else if (...) ...
}
// 正面教材:虚函数分发
class Window { public: virtual void blink() {} };
class SpecialWindow : public Window { void blink() override { ... } };
for (auto p : winPtrs) p->blink(); // 无转型,自动分发
handles = 引用/指针/迭代器。const 成员函数返回非 const handle 会破坏常量正确性。
class Rectangle {
shared_ptr<RectData> pData;
public:
// 错误:const 函数返回非 const 引用,允许修改内部状态
Point& upperLeft() const { return pData->ulhc; }
// 正确:返回 const 引用
const Point& upperLeft() const { return pData->ulhc; }
};
getX()/setX() 分离读写void PrettyMenu::changeBack(istream& imgSrc) {
Lock ml(&mutex);
auto pNew = make_shared<PMImpl>(*pImpl); // 复制副本
pNew->bgImage.reset(new Image(imgSrc)); // 修改副本(可能抛异常)
++pNew->imageChanges;
swap(pImpl, pNew); // 原子交换,不抛异常
}
函数的异常安全级别 ≤ 其调用的所有函数中最弱的级别。若调用非异常安全代码,则无法提供任何保证。