C++11運算符重載詳解與向量類重載實例(<<,>>,+,-,*等)
1. C++運算符重載介紹
C ++ 中預定義的運算符的操作對象只能是基本數據類型。但實際上,對於許多用戶自定義類型(例如類),也需要類似的運算操作。這時就必須在C ++ 中重新定義這些運算符,賦予已有運算符新的功能,使它能夠用於特定類型執行特定的操作。運算符重載的實質是函數重載,它提供了C ++ 的可擴展性,也是C ++ 最吸引人的特性之一。
運算符重載時要遵循以下規則:
( 1 ) 除了類屬關係運算符 ” . ” 、成員指針運算符 ” .* ” 、作用域運算符 ” :: ” 、sizeof運算符和三目運算符 ” ?: ” 以外,C ++ 中的所有運算符都可以重載。
( 2 ) 重載運算符限制在C ++ 語言中已有的運算符範圍內的允許重載的運算符之中,不能創建新的運算符。
( 3 ) 運算符重載實質上是函數重載,因此編譯程序對運算符重載的選擇,遵循函數重載的選擇原則。
( 4 ) 重載之後的運算符不能改變運算符的優先級和結合性,也不能改變運算符操作數的個數及語法結構。
( 5 ) 運算符重載不能改變該運算符用於內部類型對象的含義。它只能和用戶自定義類型的對象一起使用,或者用於用戶自定義類型的對象和內部類型的對象混合使用時。
( 6 ) 運算符重載是針對新類型數據的實際需要對原有運算符進行的適當的改造,重載的功能應當與原有功能相類似,避免沒有目的地使用重載運算符。
1.1 單目運算符與雙目運算符
( 1 ) 雙目運算符重載為類的成員函數時,函數只顯式說明一個參數,該形參是運算符的右操作數。
比如說你重載+號,如果寫在類外面,那麼是需要兩個參數的,而寫在類裏面,只能寫一個參數,因為當這個函數被調用的時候,會自動的傳一個this指針進去,就是對象本身,所以只需要一個參數
( 2 ) 前置單目運算符重載為類的成員函數時,不需要顯式說明參數,即函數沒有形參。
( 3 ) 後置單目運算符重載為類的成員函數時,函數要帶有一個整型形參。
比如前置++,和後置++,帶一個整形形參只是為了區分
1.2 友元運算符
有些運算符是一定得聲明為友元的,比如<<,>>運算符
因為=,+這些運算符,是c++最基本的運算符,而>>,<<運算符是標準頭文件裏面的一個類裏面寫的,你不能把這個函數聲明為你這個自定義類的函數,因為這是別人類裏面的函數,因此你只能把它聲明為友元函數,聲明為友元函數之後,那麼這個函數它就可以訪問你這個自定義類裏面的私有成員變量
2. 實例講解
光看這些概念,想必沒有接觸過的同學頭都大了,接下來我通過一個向量類的例子,來講解一下各個運算符重載怎麼用
2.1 頭文件定義
這次我們來實例一個向量類,什麼是向量類呢,就是數學裏面的向量,一個括號,裏面兩個數字,看一下頭文件你就明白啦
class Vec2D {
private:
double x_;
double y_;
public:
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
Vec2D(double x, double y) :x_(x), y_(y) {}
Vec2D() { x_ = 0.0; y_ = 0.0; }
std::string toString();
friend Vec2D operator+(const Vec2D& v1, const Vec2D& v2);
friend Vec2D operator-(const Vec2D& v1, const Vec2D& v2);
friend double operator*(const Vec2D& v1, const Vec2D& v2);
friend Vec2D operator+(const Vec2D& v1, double num);
friend Vec2D operator*(const double num, const Vec2D& v2);
friend Vec2D operator*(const Vec2D& v2, const double num);
friend istream& operator>>(istream& stream, Vec2D& v1);
friend std::ostream& operator<<(std::ostream& stream, const Vec2D& v1);
Vec2D negative();
Vec2D operator-();
Vec2D operator++();
Vec2D operator++(int dummy);
Vec2D operator--();
Vec2D operator+=(const Vec2D& v);
Vec2D operator-=(const Vec2D& v);
double& operator[](const int& index);
double magnitude();
double direction();
int compareTo(Vec2D& v2);
operator double();
double getX()const { return x_; }
double getY() const { return y_; }
void setX(double x) { x_ = x; }
void setY(double y) { y_ = y; }
};
可以看到,其實私有成員就是 x_和y_,然後我重載了非常多的函數,下面我們來看一下具體的實現
2.2 實現運算符重載
toString函數
這個函數我就不多說啦,比較簡單
std::string Vec2D::toString()
{
std::string res = "(" + std::to_string(getX()) + ", " + std::to_string(getY()) + ")";
return res;
}
negative函數
這個函數是用來將向量變成負方向
Vec2D Vec2D::negative()
{
return Vec2D(-1 * x_, -1 * y_);
}
operator-函數
第一個重載函數出現了,是重載的符號,更加方便的實現了改變向量為負方向的操作
這樣我們可以通過 -a,-b的形式來調用
Vec2D Vec2D::operator-()
{
return Vec2D(-1 * x_, -1 * y_);
}
operator++函數
這個函數是前置++運算符,返回*this就是返回當前對象
Vec2D Vec2D::operator++()
{
x_++;
y_++;
return *this;
}
operator++函數
這個函數是後置++運算符,所以後面加了一個類型的參數,這個參數唯一的意思是與前置++作區分
我們首先創建了一個臨時變量,然後將本身的x,y加1,返回的卻是臨時變量,這樣就實現了後置++的操作
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
Vec2D Vec2D::operator++(int dummy)
{
Vec2D ret(x_, y_);
x_++;
y_++;
return ret;
}
operator–函數
減減同理,就是將x,y都減1
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
Vec2D Vec2D::operator--()
{
x_ -= 1;
y_ -= 1;
return *this;
}
operator+= ,-=函數
這兩個函數比較相似,我就放到一起講啦,這裡是將調用這個函數本身的對象,與參數裏面的v相加或者相減
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
Vec2D Vec2D::operator+=(const Vec2D& v)
{
x_ += v.x_;
y_ += v.y_;
return *this;
}
Vec2D Vec2D::operator-=(const Vec2D& v)
{
x_ -= v.x_;
y_ -= v.y_;
return *this;
}
operator[ ]函數
這裡重載了[ ],有一個參數,index,用來選擇到底是返回x還是y
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
double& Vec2D::operator[](const int& index)
{
if (index == 0) {
return x_;
}
else if (index == 1) {
return y_;
}
else {
printf("subscript error\n");
exit(0);
}
}
operator+(類外)函數
因為是在類外重載,所以有兩個參數,同時要注意將這個函數聲明為友元函數,因為這樣才可以訪問私有成員變量
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
//類外重載,運算符重載函數作為類的友元函數
Vec2D operator+(const Vec2D& v1, const Vec2D& v2) {
Vec2D ret;
ret.setX(v1.getX() + v2.getX());
ret.setY(v1.getY() + v2.getY());
return ret;
}
Vec2D operator+(const Vec2D& v1, double num) {
Vec2D ret;
ret.setX(v1.getX() + num);
ret.setY(v1.getY() + num);
return ret;
}
operator*函數
這裡重載了*,用來實現向量之間的相乘
static string AuthorBlog = "//www.cnblogs.com/wanghongyang";
Vec2D operator*(const double num, const Vec2D& v2) {
Vec2D ret;
ret.setX(num * v2.getX());
ret.setY(num * v2.getY());
return ret;
}
重載>> <<
這裡給大家避個坑,一定要引入iostream頭文件,而不是用using
這兩個函數就是用來實現cout和cin
可以看到,實現cin 是通過 istream對象來實現的
實現cout 是通過ostream來實現的
記得在最後返回istream或者ostream對象
istream& operator>>(istream& stream, Vec2D& v1)
{
double x, y;
stream >> x >> y;
v1.setX(x);
v1.setY(y);
// 也可以直接
// stream >> x_ >> y_;
return stream;
}
ostream& operator<<(ostream& stream, const Vec2D& v1)
{
std::string res = "(" + std::to_string(v1.getX()) + ", " + std::to_string(v1.getY()) + ")";
stream << res;
return stream;
}