一個模擬Point點的類,內置函數類型爲int.
實現默認構造,自定義構造,拷貝構造、移動構造,拷貝賦值、移動賦值
重載成員運算符函數 “operator+=”、“operator+”、“operator<<”
重載非成員運算法函數 “operator*”
1、類的聲明
class TestOperatorPoint {
public:
// default
TestOperatorPoint() = default;
TestOperatorPoint(int x, int y) :
x(x), y(y) //參數名、成員變量可以同名
{}
// copy constructor
TestOperatorPoint(const TestOperatorPoint& pt);
// move constructor
TestOperatorPoint(TestOperatorPoint&& pt);
//// 錯誤的拷貝賦值
//TestOperatorPoint operator=(const TestOperatorPoint& pt);
// copy assign
TestOperatorPoint& operator=(const TestOperatorPoint& pt);
// move assign
TestOperatorPoint& operator=(TestOperatorPoint&& pt);
////////////////// operations
TestOperatorPoint operator+(const TestOperatorPoint& pt)
TestOperatorPoint& operator+=(const TestOperatorPoint& pt);
// 輸出重載(友元函數)
friend std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt);
//private:
int x, y;
};
2、類的具體實現
2.1 構造函數和賦值函數
以下類定義時的實現,類定義外實現是需要加類作用域。
// copy constructor
TestOperatorPoint(const TestOperatorPoint& pt)
{
std::cout << "copy constructor" << std::endl;
x = pt.x;
y = pt.y;
}
// move constructor
TestOperatorPoint(TestOperatorPoint&& pt)
{
std::cout << "move constructor" << std::endl;
x = std::move(pt.x); // x,y是基本類型,移動時不影響
y = std::move(pt.y);
}
//// 錯誤的拷貝賦值
//TestOperatorPoint operator=(const TestOperatorPoint& pt)
//{
// std::cout << "wrong copy assign" << std::endl;
// // x = pt.x;
// //y = pt.y;
// // return *this; // 如果不返回引用,會將*this對象進行一次拷貝賦值,
// return pt; // 直接返回也會再進行一次拷貝賦值,
//}
// copy assign
TestOperatorPoint& operator=(const TestOperatorPoint& pt)
{
std::cout << "copy assign" << std::endl;
x = pt.x;
y = pt.y;
return *this;
}
// move assign
TestOperatorPoint& operator=(TestOperatorPoint&& pt)
{
std::cout << "move assign" << std::endl;
x = std::move(pt.x); // x,y是基本類型,移動時不影響;
y = std::move(pt.y);
return *this;
}
需要說明的是,當成員變量是非基本類型,如string、vector、指針對象以及其他類對象時,move的作用在於減少過多的構造、賦值操作。
例如,如下操作
string str1 = "abc";
string str2 = std::move(str1)
結果是 str1爲"",str2爲"abc"。 str2進行的是移動構造。
測試代碼
TestOperatorPoint pt1;
TestOperatorPoint pt2(3, 4); //自定義構造
TestOperatorPoint pt3(pt2); // 拷貝構造
pt1 = pt2; // 拷貝賦值, pt1已經存在
TestOperatorPoint pt4;
TestOperatorPoint pt5(1, 1);
TestOperatorPoint pt6(2, 2);
TestOperatorPoint pt7(std::move(pt5)); // 移動構造
pt4 = std::move(pt6); // 拷貝賦值, pt4已經存在
2.2 類成員操作符重載(包括友元函數)
- 賦值(=)、下標([ ])、調用( ( ) )和成員訪問箭頭( -> )必須是成員函數;
- 改變對象狀態、遞增遞減、解引用等與自身類型密切相關的運算符,通常是成員函數;
////////////////// operations
TestOperatorPoint operator+(const TestOperatorPoint& pt)
{
TestOperatorPoint tmp;
tmp.x = x + pt.x;
tmp.y = y + pt.y;
return tmp; // 返回局部臨時變量,編譯器優化爲 移動操作,不要畫蛇添足
}
TestOperatorPoint& operator+=(const TestOperatorPoint& pt)
{
x += pt.x;
y += pt.y;
return *this; // 明確是對自己要修改,要返回引用。否則多一次拷貝構造。
}
操作符重載的測試代碼,如下
TestOperatorPoint pt1(1, 2);
TestOperatorPoint pt2(3, 4);
// 移動構造(先執行pt1的操作符重載成員函數,返回臨時變量進行移動構造)
TestOperatorPoint pt3 = pt1 + pt2;
TestOperatorPoint pt4(0,0);
pt4 += pt1; // 僅調用pt4的+=函數
2.3 普通的非成員操作符重載
- 算術、相等、關係和位運算,以及可以轉換任意一端的運算符對象,應該定義爲普通的普通的非成員操作符重載。
- 輸入輸出運算符必須是普通的非成員函數。
2.3.1 operator*(const TestOperatorPoint& pt, T v)和operator*(T v,const TestOperatorPoint& pt)
例如,一個TestOperatorPoint對象,僅想將其成員變量x,y同時擴大一個倍數(可以是int, float, double等非類內置類型int),這種情況可以定義爲
// 混合類型表達式定義爲普通的非成員函數(第二個參數不是同一個類類型)
template<typename T>
TestOperatorPoint operator*(const TestOperatorPoint& pt, T v)
{
TestOperatorPoint tmp;
tmp.x = pt.x * v; // 會強轉爲TestOperatorPoint.x的成員類型
tmp.y = pt.y * v;
return tmp;
}
測試使用 TestOperatorPoint pt5 = pt4 * 3.14;
,是沒有問題;
但是如果我們先交換乘法順序(對稱性),如TestOperatorPoint pt6 = 3.14 * pt4;
這裏是無法執行的,因爲 3.14 是double類型,是沒有定義重載operator*(TestOperatorPoint)
函數的,因此我們需要定義如下普通操作符函數
// 上面乘法運算的重載,對稱性
template<typename T>
TestOperatorPoint operator*(T v, const TestOperatorPoint& pt)
{
TestOperatorPoint tmp;
tmp.x = pt.x * v; // 會強轉爲TestOperatorPoint.x的成員類型
tmp.y = pt.y * v;
return tmp;
}
此時,TestOperatorPoint pt6 = 3.14 * pt4;
能夠正常執行。
2.3.2 重載輸入操作符函數 operator<<
通常自定義打印輸出的<<函數時,需要訪問類的非公有數據成員,因此定義爲友元函數。若不需要,可以定義爲非友元函數。
自定義打印輸入重載運算符。
// 輸出重載(定義時實現)
friend std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt);
{
out << "[" << pt.x << ", " << pt.y << "]";
return out;
}
當在外部實現友元函數時,函數不要加類的作用域。
std::ostream& operator<< (std::ostream& out, const TestOperatorPoint& pt)
{
out << "[" << pt.x << ", " << pt.y << "]";
return out;
}
例如測試,std::cout << pt4 << std::endl;