重载(overload)让同一个名字可以做不同的事。函数重载让同名函数处理不同类型;运算符重载让
+、*等符号作用于自定义类型。理解它,你才明白为什么 Eigen 能写m * v、m << 1,2。
13.1 函数重载:同名函数
C++ 允许多个同名函数,只要它们的参数不同(个数或类型不同):
#include<iostream>intadd(inta,intb){// 两个 intreturna+b;}doubleadd(doublea,doubleb){// 两个 doublereturna+b;}intadd(inta,intb,intc){// 三个 intreturna+b+c;}intmain(){std::cout<<add(3,5)<<std::endl;// 调第一个,8std::cout<<add(3.5,1.5)<<std::endl;// 调第二个,5std::cout<<add(1,2,3)<<std::endl;// 调第三个,6}编译器根据实参的类型和个数,自动决定调用哪个版本。这就是函数重载。
规则:重载靠"参数"区分,和返回类型无关。两个函数参数完全相同、只有返回类型不同,是不允许的。
13.2 运算符重载:给符号赋予新含义
C++ 允许给自定义类型定义运算符(+ - * / << ==等)的行为,让代码像数学公式一样自然。
重载+:两个向量相加
#include<iostream>structVec2{doublex,y;// 重载 + :成员函数形式Vec2operator+(constVec2&other)const{Vec2 result;result.x=x+other.x;result.y=y+other.y;returnresult;}};intmain(){Vec2 a{1,2};Vec2 b{3,4};Vec2 c=a+b;// 自动调用 a.operator+(b)std::cout<<c.x<<" "<<c.y<<std::endl;// 4 6}operator+是特殊函数名,表示"定义 + 号的行为"。a + b就等价于a.operator+(b)。
重载*:向量乘标量
structVec2{doublex,y;Vec2operator*(doublescale)const{returnVec2{x*scale,y*scale};}};Vec2 v{2,3};Vec2 w=v*2;// {4, 6}重载<<:打印自定义类型
std::cout << v想打印自定义类型,需要重载<<。因为左边是std::cout,不能用成员函数,要用自由函数:
#include<iostream>structVec2{doublex,y;};// 重载 << :自由函数形式std::ostream&operator<<(std::ostream&os,constVec2&v){os<<"("<<v.x<<", "<<v.y<<")";returnos;// 返回 os,支持连续 <<}intmain(){Vec2 v{1,2};std::cout<<v<<std::endl;// (1, 2)}13.3 运算符重载的两种形式
| 形式 | 适用 | 例子 |
|---|---|---|
| 成员函数 | 左操作数是本类对象 | a + b→a.operator+(b) |
| 自由函数 | 左操作数不是本类(如 cout) | cout << v→operator<<(cout, v) |
13.4 Eigen 里的运算符重载
现在你就能看懂 Eigen 的魔法了。Eigen 内部重载了一大堆运算符:
Eigen::Matrix2d m;m<<1,2,// << 被重载成"逗号初始化"3,4;Eigen::Vector2dv(1,1);Eigen::Vector2d result=m*v;// * 被重载成"矩阵乘向量"Eigen::Matrix2d sum=m+m;// + 被重载成"对应元素相加"doubleelem=m(0,1);// () 被重载成"取元素"std::cout<<m<<std::endl;// << 被重载成"打印矩阵"m * v→ 调m.operator*(v)(矩阵乘法)m + m→ 调m.operator+(m)(逐元素加)m(0,1)→ 调m.operator()(0,1)(取元素)m << 1,2→ 调m.operator<<(...)(逗号初始化)
没有运算符重载,Eigen 的代码会变成一长串m.multiply(v)、m.add(n),难读难写。重载让 Eigen 的代码和数学公式几乎一模一样,这正是它的魅力所在。
13.5 小结
- 函数重载:同名函数靠参数区分。
- 运算符重载:
operator+、operator*等给符号定义行为。 - 成员函数形式
a.operator+(b),自由函数形式operator<<(cout, v)。 - Eigen 的
m*v、m << 1,2、m(0,1)全靠运算符重载实现。
下一章,学习模板——Eigen 能"一套代码支持所有类型"的核心机制。
练习题
- 重载
add函数,分别支持 int 和 double 版本。 - 定义一个
Vec2,重载+和*(乘标量)。 - 重载
<<,让std::cout能直接打印Vec2。 - 重载
==,判断两个Vec2是否相等。 - 说说 Eigen 的
m * v内部发生了什么。