C++语言学习(八)——操作符重载

C++语言学习(八)——操作符重载

一、操作符重载基础

1、操作符重载的语法

通过operator关键字可以定义特殊的函数,operator本质是通过函数重载操作符。

Type operator operatorname(const Type p1, const Type p2)
{
    Type ret;

    return ret;
}

2、友元函数重载操作符

可以将操作符重载函数声明为友元函数。

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x=0, float y=0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    friend const Complex operator+(const Complex &c1,const Complex &c2);
private:
    float x;
    float y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
    return Complex(c1.x + c2.x,c1.y + c2.y);
}
int main(int argc, char *argv[])
{
    Complex c1(2,3);
    Complex c2(3,4);
    c1.print();
    c2.print();
    Complex c3 = c1 + c2;
    c3.print();
    Complex c4 = operator+(c1,c2);
    c4.print();

    return 0;
}

上述代码中,编译器会检查是否有可用的操作符重载函数,因此Complex c3 = c1 + c2;代码也是合法的。

3、成员函数重载操作符

将操作符重载函数定义为类成员函数。

#include <iostream>

using namespace std;

class Complex
{
public:
    Complex(float x=0, float y=0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    const Complex operator+(const Complex &another)
    {
        cout << "member function." << endl;
        return Complex(this->x + another.x, this->y + another.y);
    }
    friend const Complex operator+(const Complex &c1,const Complex &c2);
private:
    float x;
    float y;
};
const Complex operator+(const Complex &c1,const Complex &c2)
{
    cout << "friend global function." << endl;
    return Complex(c1.x + c2.x,c1.y + c2.y);
}
int main(int argc, char *argv[])
{
    Complex c1(2,3);
    Complex c2(3,4);
    c1.print();
    c2.print();
    //成员函数
    Complex c3 = c1 + c2;
    c3.print();
    //成员函数
    Complex c4 = c1.operator +(c2);
    c4.print();
    //全局函数
    Complex c5 = operator+(c1,c2);
    c4.print();

    return 0;
}

操作符重载函数作为类的成员函数时,比全局操作符重载函数少一个参数,不需要依赖友元就可以完成操作符重载,编译器会优先在类的成员函数中查找操作符重载函数。因此Complex c3 = c1 + c2;代码会优先调用类的操作符重载成员函数。

4、操作符重载的规则

操作符重载的规则:
A、C++不允许用户自己定义新的运算符,只能对已有的 C++运算符进行重载。
B、C++语言中大部分运算符都可以重载,成员选择符(.)、成员对象选择符(.*)、域解析操作符(::)、条件操作符(?:)、sizeof不可以重载。除了赋值操作符(=)外,基类中重载的操作符都将被派生类继承。
C、重载不能改变运算符运算对象(即操作数)的个数。
D、重载不能改变运算符的优先级别。
E、重载不能改变运算符的结合性。
F、重载运算符的函数不能有默认的参数
G、重载的运算符必须和用户定义的自定义类型的对象一起使用,其参数至少应有一个是类对象(或类对象的引用)。参数不能全部是 C++的标准类型,以防止用户修改用于标准类型数据成员的运算符的性质。
H、用于类对象的运算符一般必须重载,但有两个例外,运算符”=“和运算符”&“不必用户重载。
I、应当使重载运算符的功能类似于该运算符作用于标准类型数据时候时所实现的功能。
J、运算符重载函数可以是类的成员函数,也可以是类的友元函数,还可以是既非类的成员函数也不是友元函数的普通函数。
K、赋值操作符只能重载为成员函数

二、操作符重载实例

1、双目运算符重载

形式:L#R
全局函数:operator#(L,R);
成员函数:L.operator#(R)
operator+=实例:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(double x = 0, double y = 0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    Complex& operator +=(const Complex &c)
    {
        this->x += c.x;
        this->y += c.y;
        return * this;
    }
private:
    double x;
    double y;
};

2、单目运算符重载

形式:#M 或 M#
全局函数:operator#(M)
成员函数:M.operator#()
operator-实例:

#include <iostream>
using namespace std;
class Complex
{
public:
    Complex(double x = 0, double y = 0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    const Complex operator-(void) const
    {
        return Complex(-x,-y);
    }
private:
    double x;
    double y;
};

3、流输入输出运算符重载

函数形式

    istream & operator>>(istream &,自定义类&);
    ostream & operator<<(ostream &,自定义类&);

流输入输出运算符重载通过友元来实现,避免修改C++的标准库。
operator<< 和operator>>实例:

class Complex
{
public:
    Complex(double x = 0, double y = 0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    friend ostream & operator<<(ostream &os, const Complex & c);
    friend istream & operator>>(istream &is, Complex &c);
private:
    double x;
    double y;
};
ostream & operator<<(ostream &os, const Complex & c)
{
    os<<"("<<c.x<<","<<c.y<<")";
    return os;
}
istream & operator>>(istream &is, Complex &c)
{
    is>>c.x>>c.y;
    return is;
}

三、操作符重载总结

1、不可以重载的操作符

. (成员访问运算符)
.* (成员指针访问运算符)
:: (域运算符)
sizeof (长度运算符)
?: (条件运算符)

2、只能重载为成员函数的运算符

= 赋值运算符
[] 下标运算符
() 函数运算符
-> 间接成员访问
编译器默认重载了赋值运算符,但编译器默认重载的赋值操作符仅完成浅拷贝,需要深拷贝操作必须自定义重载赋值操作符。

3、运算符重载与友元

A、一个操作符的左右操作数不一定是相同类型的对象,这就涉及到将该操作符函数定义为谁的友元,谁的成员问题。
B、一个操作符函数,被声明为哪个类的成员,取决于该函数的调用对象(通常是左操作数)。
C、一个操作符函数,被声明为哪个类的友员,取决于该函数的参数对象(通常是右操作数)。

#include <iostream>
using namespace std;
class Mail;
class Sender
{
public:
    Sender(string s):_addr(s){}
    Sender& operator<<(const Mail & mail); //成员
private:
    string _addr;
};
class Mail
{
public:
    Mail(string _t,string _c ):_title(_t),_content(_c){}
    friend Sender& Sender::operator<<(const Mail & mail);
    //友元
private:
    string _title;
    string _content;
};
Sender& Sender::operator<<(const Mail & mail)
{
    cout<<"Address:"<<mail._addr<<endl;
    cout<<"Title :"<<mail._title<<endl;
    cout<<"Content:"<<mail._content<<endl;
    return *this;
}
int main()
{
    Sender sender("[email protected]");
    Mail mail("note","meeting at 3:00 pm");
    Mail mail2("tour","One night in beijing");
    sender<<mail<<mail2;
    return 0;
}

5、操作符重载的陷阱

A、逻辑运算操作符:
运算符重载本质是函数重载,C++对逻辑操作符重载时将逻辑操作符定义为函数,但是由于函数参数的计算次序是不确定的,导致逻辑操作符原生的短路法则将失效,因此不推荐对逻辑操作符进行重载。工程实践中需要使用重载比较操作符等方法避免重载逻辑操作符的陷阱,直接使用成员函数代替逻辑操作符重载,使用全局函数对逻辑操作符进行重载。

#include <iostream>

using namespace std;

class Test
{
public:
    Test(int ok = true)
    {
        this->ok = ok;
    }
    int value()const
    {
        cout << "call value(),ok = " << ok << endl;
        return ok;
    }
    Test operator +(const Test& another)
    {
        this->ok += another.ok;
        return *this;
    }
private:
    int ok;
};
//&&操作符重载函数
bool operator &&(const Test& left, const Test& right)
{
    return left.value() && right.value();
}
//||操作符重载函数
bool operator ||(const Test& left, const Test& right)
{
    return left.value() || right.value();
}

Test func(Test test)
{
    cout << "Test func(Test test): i = "<< test.value() <<endl;
    return test;
}

int main(int argc, char *argv[])
{
    Test test0(0);
    Test test1(1);
    Test test2(2);
    Test test3(3);
    if(test0 && test1)
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    /*****************************
     *call value(),ok = 0
     *result is false
     * 上述测试代码:短路法则正常
     * **************************/
    cout << endl;
    if(operator &&(func(test0), func(test1)))
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    cout << endl;
    /*****************************
     *call value(),ok = 1
     *Test func(Test test): i = 1
     *call value(),ok = 0
     *Test func(Test test): i = 0
     *call value(),ok = 0
     *result is false
     *上述测试代码:短路法则失效
     * **************************/
    if((test2 + test3) && test0)
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    cout << endl;
    /*****************************
     *call value(),ok = 5
     *call value(),ok = 0
     *result is false
     * **************************/
    if(test0 || test1)
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    cout << endl;
    /*****************************
     *call value(),ok = 0
     *call value(),ok = 1
     *result is true
     * **************************/
    if(operator &&(test0, test1))
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    cout << endl;
    /*****************************
     *call value(),ok = 0
     *result is false
     *上述测试代码:短路法则正常
     * **************************/
    if(operator ||(test0 + test1, test3))
    {
        cout << "result is true" << endl;
    }
    else
    {
        cout << "result is false" << endl;
    }
    /*****************************
     *call value(),ok = 1
     *result is true
     *上述测试代码:短路法则正常
     * **************************/

    return 0;
}

上述测试代码中,如果逻辑操作符的操作数中是需要计算的函数调用,短路法则可能会失效。
B、逗号操作符:
可以使用全局函数对逗号操作符进行重载,重载函数的参数必须有一个是类类型,返回值类型必须是引用。

class& operator,(const class& a, const class& b)
{
    return const_cast<class&>(b);
}

重载逗号操作符后,逗号表达式无法严格从左向右计算表达式,不能重载逗号操作符,重载后的逗号操作符没有了原生的语义。
原因:操作符的重载本质是函数调用,函数调用在进入函数体前需要完成所有参数的计算,参数的计算次序是不确定的,因此重载逗号操作符后无法保证逗号操作符的原生语义。
逗号操作符不需要重载,重载的逗号操作符无法严格从左向右计算逗号表达式,失去了原生逗号操作符的语义。
C、前置操作符与后置操作符
前置操作符和后置操作符支持全局函数、类成员函数重载。
前置的++、--运算操作符可以重载,不需要额外的参数。
后置的++、--运算操作符可以重载,需要一个int类型的占位参数。

#include <iostream>

using namespace std;

class Test
{
public:
    Test(int i = 0)
    {
        this->i = i;
    }
    //前置操作符++
    Test& operator ++()
    {
        ++i;
        return *this;
    }
    //前置操作符--
    Test& operator --()
    {
        --i;
        return *this;
    }
    //后置操作符--
    Test operator ++(int)
    {
        Test ret(i);
        i++;
        return ret;
    }
    //后置操作符--
    Test operator --(int)
    {
        Test ret(i);
        i--;
        return ret;
    }
    int value()const
    {
        return i;
    }
private:
    int i;
};

int main(int argc, char *argv[])
{
    Test test1(1);
    cout << (++test1).value() << endl;
    Test test2(1);
    cout << (--test2).value() << endl;
    Test test3(1);
    cout << (test3++).value() << endl;
    Test test4(1);
    cout << (test4--).value() << endl;

    return 0;
}

由于类的前置操作符重载函数内部没有额外的临时对象开销,类的前置操作符重载函数效率比后置操作符高。

    int i = 0;
    i++;
    ++i;

对于C++基础类型,前置操作符和后置操作符效率基本相同。
现代C++编译器会对编译代码进行优化,使得编译后的二进制代码更加高效,优化后的二进制代码可能失去C/C++代码的原生语义。

三、类型转换

1、类型转换简介

C++语言中,标准类型之间的转换一般有隐式和显示转换,用户自定义类型间的转换则需要自定义专门的转换函数。
C语言中,基本类型间会进行隐式的类型安全转换,转换规则如下:

 int a = -2000;
 unsigned int b = 1000;
 cout << a + b << endl;//4294966296

上述代码中,int与unsigned int运算时int会被转换为unsigned int,此时a会被转换为unsigned int,是一个非常大的数。

short s = 12;
char c = ‘1‘;
cout << sizeof(s + c) << endl;//4

上述代码中,C++编译器会进行优化,编译器遇到short与char进行运算时会将short和char都转换为int,便于高效计算。
C++语言兼容了C语言的隐式类型安全转换。

2、标准类型间转换

基本类型间的转换如下:
A、隐式转换
5.0/8
B、显示转换
(float)5/8

3、C++类类型的转换

C++的类类型之间的转换的规则如下:
A、转换函数定义在源对象类(待转换对象中)中,是转换源的成员函数。
B、一旦为转换源类型提供了到目标类型的转化操作符函数,就可以将源类型对象以隐式转化的方式得的目标类型的对象。
C、应用于构造及初始化,赋值,传参,返回等等场合。

#include <iostream>

using namespace std;

class Test
{
public:
    Test(int i = 0)
    {
        this->i = i;
        cout << "Test(int i = 0) i = " << i << endl;
    }
private:
    int i;
};

int main(int argc, char *argv[])
{
    Test test;//Test(int i = 0) i = 0
    test = 10;//Test(int i = 0) i = 10

    return 0;
}

上述代码中,编译器会将10使用构造函数Test(int i = 0)隐式转换为Test对象。
实际工程中类的隐式类型转换是不安全的,编译器会尽力去查找构造函数转化不同的类型,如果没有匹配的构造函数才会报错,因此不可以使用隐式类型转换,需要使用explicit关键字声明编译器不能隐式类型转换,而需要显示的声明类型转换。
显示声明类对象类型转换的使用方式:

static_cast<classname>(value);
classname(value);
(calssname)value;//不推荐
#include <iostream>

using namespace std;

class Test
{
public:
    explicit Test(int i = 0)
    {
        this->i = i;
        cout << "Test(int i = 0) i = " << i << endl;
    }
private:
    int i;
};

int main(int argc, char *argv[])
{
    Test test;//Test(int i = 0) i = 0
    test = static_cast<Test>(10);//Test(int i = 0) i = 10
    test = Test(100);//Test(int i = 0) i = 100

    return 0;
}

上述代码中,构造函数使用explicit关键字进行声明,编译器不能再进行隐式的类型转换,只能使用显示的类型转换。

4、用类型转换构造函数进行类型转换

类型转换构造函数声明如下:
classname(const anotherclass & another);

#include <iostream>

using namespace std;

class Point3D;
class Point2D
{
public:
    Point2D(int x = 0,int y = 0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
    friend class Point3D;
private:
    int x;
    int y;
};
class Point3D
{
public:
    Point3D(int x = 0, int y = 0, int z = 0)
    {
        this->x = x;
        this->y = y;
        this->z = z;
    }
    //类型转换构造函数
    Point3D(const Point2D &p)
    {
        this->x = p.x;
        this->y = p.y;
        this->z = 0;
        cout << "Point3D(const Point2D &p)" <<endl;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<","<<z<<")"<<endl;
    }
private:
    int x;
    int y;
    int z;
};

int main(int argc, char *argv[])
{
    Point2D p2(1,2);
    p2.print();
    Point3D p3(3,4,5);
    p3.print();
    Point3D p3a = p2;//Point3D(const Point2D &p)
    p3a.print();

    return 0;
}

上述代码中,Point3D类提供了一个类型转换构造函数,用于将Point2D类对象转换为Point3D类型。

5、用类型转换操作符函数进行转换

类型转换函数可以将类对象转换为其它类型。
类型转换函数声明的语法如下:
operator Type(void);

#include <iostream>

using namespace std;

class Point3D;
class Point2D
{
public:
    explicit Point2D(int x = 0,int y = 0)
    {
            this->x = x;
            this->y = y;
    }
    void print()
    {
            cout<<"("<<x<<","<<y<<")"<<endl;
    }
private:
    int x;
    int y;
    friend class Point3D;
};
class Point3D
{
public:
    explicit Point3D(int x = 0, int y = 0, int z = 0)
    {
            this->x = x;
            this->y = y;
            this->z = z;
    }
    //类型转换构造函数
    Point3D(const Point2D &p)
    {
            this->x = p.x;
            this->y = p.y;
            this->z = 0;
            cout << "Point3D(const Point2D &p)" <<endl;
    }
    operator Point2D()
    {
            cout << "operator Point2D()" << endl;
            Point2D p2;
            p2.x = x;
            p2.y = y;
            return p2;
    }
    void print()
    {
            cout<<"("<<x<<","<<y<<","<<z<<")"<<endl;
    }
private:
    int x;
    int y;
    int z;
};

int main(int argc, char *argv[])
{
    Point3D p3(3,4,5);
    p3.print();
    Point2D p2(1,2);
    p2.print();

    Point2D p2a = p3;//operator Point2D()
    p2a.print();

    return 0;
}

上述代码中,使用Point3D对象对Point2D对象进行初始化时会调用operator Point2D()类型转换操作符函数。
类型转换操作符函数可能和类型转换构造函数冲突,可以使用explicit对类型转换构造函数声明避免冲突。工程中实际使用普通的classname toClassName()公有成员函数进行类型转换。

#include <iostream>

using namespace std;

class Point3D;
class Point2D
{
public:
    explicit Point2D(int x = 0,int y = 0)
    {
        this->x = x;
        this->y = y;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<")"<<endl;
    }
private:
    int x;
    int y;
    friend class Point3D;
};
class Point3D
{
public:
    explicit Point3D(int x = 0, int y = 0, int z = 0)
    {
        this->x = x;
        this->y = y;
        this->z = z;
    }
    //类型转换构造函数
    Point3D(const Point2D &p)
    {
        this->x = p.x;
        this->y = p.y;
        this->z = 0;
        cout << "Point3D(const Point2D &p)" <<endl;
    }
    operator Point2D()
    {
        cout << "operator Point2D()" << endl;
        Point2D p2;
        p2.x = x;
        p2.y = y;
        return p2;
    }
    Point2D toPoint2D()
    {
        Point2D p2;
        p2.x = x;
        p2.y = y;
        return p2;
    }
    void print()
    {
        cout<<"("<<x<<","<<y<<","<<z<<")"<<endl;
    }
private:
    int x;
    int y;
    int z;
};

int main(int argc, char *argv[])
{
    Point3D p3(3,4,5);
    p3.print();
    Point2D p2(1,2);
    p2.print();

    Point2D p2a = p3;//operator Point2D()
    p2a.print();

    Point2D p2b = p3.toPoint2D();
    p2b.print();

    return 0;
}

五、操作符重载应用

1、函数操作符

函数对象也成仿函数(functor),可以使用具体的类对象取代类成员函数。函数对象通过重载函数操作符实现,函数操作符只能重载为类的成员函数,可以定义不同参数的多个重载函数。
函数操作符重载函数声明如下:
Type operator()()
函数操作符主要应用于STL和模板。函数操作符只能通过类成员函数重载,函数对象用于在工程中取代函数指针。

#include <iostream>
using namespace std;

class Fib
{
 private:
    int a0;
    int a1;
public:
    Fib()
    {
        a0 = 0;
        a1 = 1;
    }
    Fib(int n)
    {
        a0 = 0;
        a1 = 1;
        for(int i = 0; i < n; i++)
        {
            int t = a1;
            a1 = a0 + a1;
            a0 = t;
        }
    }
    int operator()()
    {
        int ret = a1;
        a1 = a0 + a1;
        a0 = ret;
        return ret;
    }
};

int main()
{
    Fib fib;
    for(int i = 0; i < 10; i++)
    {
        cout << fib() << endl;
    }
    cout << endl;
    Fib fib2(10);//从第10项开始
    for(int i = 0; i < 5; i++)
    {
        cout << fib2() << endl;
    }
    return 0;
}

2、堆内存操作符

定义:

operator new
operator delete
operator new[]
operator delete[]

A、全局函数重载

#include <iostream>
#include <stdlib.h>
using namespace std;

class A
{
public:
    A()
    {
        cout<<"A constructor"<<endl;
    }
    ~A()
    {
        cout<<"A destructor"<<endl;
    }
private:
    int a;
};

void * operator new (size_t size)
{
    cout<<"new "<<size<<endl;
    return malloc(size);
}
void operator delete(void *p)
{
    cout<<"delete"<<endl;
    free(p);
}
void * operator new[] (size_t size)
{
    cout<<"new[] "<<size<<endl;
    return malloc(size);
}
void operator delete[](void *p)
{
    cout<<"delete[] "<<endl;
    free(p);
}

int main()
{
    int *p = new int;
    delete p;
    int *pa = new int[20];
    delete []pa;
    A * cp = new A;
    delete cp;
    A * cpa = new A[20];
    delete []cpa;
    return 0;
}

B、类成员函数重载

#include <iostream>
#include <stdlib.h>
using namespace std;

class A
{
public:
    A()
    {
        cout<<"A constructor"<<endl;
    }
    ~A()
    {
        cout<<"A destructor"<<endl;
    }
    void * operator new (size_t size)
    {
        cout<<"new "<<size<<endl;
        return malloc(size);
    }
    void operator delete(void *p)
    {
        cout<<"delete"<<endl;
        free(p);
    }
    void * operator new[] (size_t size)
    {
        cout<<"new[] "<<size<<endl;
        return malloc(size);
    }
    void operator delete[](void *p)
    {
        cout<<"delete[] "<<endl;
        free(p);
    }
    private:
        int a;
};

int main()
{
    // int *p = new int;
    // delete p;
    // int *pa = new int[20];
    // delete []pa;
    A * cp = new A;
    delete cp;
    A * cpa = new A[20];
    delete []cpa;
    return 0;
}

3、赋值操作符重载

编译器默认为每个类重载了赋值操作符,但默认的赋值操作符只完成浅拷贝。与拷贝构造函数一样,当需要深拷贝时需要显示重载赋值操作符。

#include <iostream>
using namespace std;

class Test
{
private:
    int* pointer;
public:
    Test()
    {
        pointer = NULL;
    }
    Test(int n)
    {
        pointer = new int(n);
    }
    Test(const Test& another)
    {
        pointer = new int(*another.pointer);
    }
    Test& operator=(const Test& another)
    {
        if(this != &another)
        {
            delete pointer;
            pointer = new int(*another.pointer);
        }
        return *this;
    }
    void print()
    {
        cout << this << endl;
    }

};

int main()
{
    Test t1 = 1;
    Test t2 = t1;
    Test t3;
    t3 = t2;
    t1.print();
    t2.print();
    t3.print();
    return 0;
}

4、下标访问操作符重载``

下标访问操作符([])只能通过类的成员函数重载,并且重载函数只能使用一个参数。
#include <iostream>
#include <sstream>
#include <string>

using namespace std;

class Test
{
int m_array[5];
public:
//使用位置索引作为下标访问
int& operator [](int index)
{
return m_array[index];
}
//使用字符串作为下标访问
int& operator [](const char* index)
{
if(index == "1st")
{
return m_array[0];
}
if(index == "2nd")
{
return m_array[1];
}
if(index == "3rd")
{
return m_array[2];
}
if(index == "4th")
{
return m_array[3];
}
if(index == "5th")
{
return m_array[4];
}
return m_array[0];
}
int length()const
{
return sizeof(m_array)/sizeof(int);
}
};

int main(int argc, char *argv[])
{
Test test;
for(int i = 0; i < test.length(); i++)
{
test[i] = i;
}
for(int i = 0; i < test.length(); i++)
{
cout << test[i] << endl;
}

cout << test["1st"] << endl;
cout << test["2nd"] << endl;
cout << test["3rd"] << endl;
cout << test["4th"] << endl;
cout << test["5th"] << endl;
return 0;

}

原文地址:http://blog.51cto.com/9291927/2143237

时间: 2024-10-05 09:24:56

C++语言学习(八)——操作符重载的相关文章

C语言学习--八皇后问题

问题描述: 在8X8格的国际象棋上摆放八个皇后,使其不能互相攻击,即任意两个皇后都不能处于同一行.同一列或同一斜线上,问有多少种摆法. 程序设计: 1.一维数组a[17],数组分成三段,第一段a[0]用来标记八皇后安置完成:第二段a[1,8]用来标记列位置有无子,方便判断列冲突:第三段a[9,16]用来标记存储位置. 2.关键算法 递归判断位置,eightQueens . 3.对角线位置互斥判断, isDiagonal. 4.输出函数, printResult. 算法描述: 1.首次传入为数组a

C++学习笔记-操作符重载

操作符重载(operator overloading)是一种形式的C++多态,C++将操作符重载扩展到用户自定义的类型,如允许使用+将两个自定义的对象相加,编译器将根据操作数的数目和类型决定使用那种加法定义. 要重载操作符,需使用操作符函数,格式如下: operator op (argument-list) op:要重载的操作符 argument-list: 操作数 操作符函数可以是类的成员函数,也可以是友元函数,如果是类成员函数,则第一个操作数是调用对象,它不在argument-list中.

【学习】操作符重载

2018/8/21 15:16:56 何为操作符重载? 1. 操作符重载就是为了让原有操作符能够作用于用户定义的类型,例如'+'操作符原来只能用于两侧均为数字或字符串的情况,通过操作符重载可以实现如两个时刻相加求和(类似11:20:00 + 1:25:20). 1 class Time(object): 2 def __init__(self,hour=0,minute=0,second=0): 3 self.hour = hour 4 self.minute = minute 5 self.h

C语言学习(四)--操作符

算数操作符 + 加 - 减 * 乘 / 除 % 取模 移位操作符 >> 右移 << 左移 位操作符 & 按位与操作,只有两个位都是1,才是1,否则是0 | 按位或操作,只有两个位都是0,才是0,否则是1 ^ 按位异或操作,如果两个位不一样结果为1,如果相同,结果为0 复合赋值符 += -= *= /= %= <<= >>= &= ^= |= 比如a += b 就是a = a+b,其它的复合赋值符操作相似. 单目操作符 ! 逻辑取反 ++ c=

C++等号操作符重载

在新学操作符重载时最令人头疼的可能就是一些堆溢出的问题了,不过呢,只要一步步的写好new 与 delete.绝对不会有类似的问题. 当时我们编译可以通过,但是运行会出错,因为对象s1与s2进行赋值时,采用浅拷贝,导致对象析构时会对同一块内存空间析构两次.也就是说等号操作符“=”,默认是进行浅拷贝,我们需要对等号操作符进行重载,使其能够进行深拷贝. 同时要重载等号操作符支持链式编程,类如 s3 = s4 = s5;  //操作符使对象连载叠加,与上一篇的return *this 与 return

C++语言学习(十八)——异常处理

C++语言学习(十八)--异常处理 一.C语言异常处理 异常是指程序在运行过程中产生可预料的执行分支.如除0操作,数组访问越界.要打开的文件不存在.Bug是指程序中的错误,是不被预期的运行方式.如野指针.堆空间使用结束未释放.C语言中处理异常的方式一般是使用if....else...分支语句. double divide(double a, double b) { const double delta = 0.000000000000001; double ret = 0; if( !((-de

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符、成员函数方式重载、友元函数方式重载

C++ Primer 学习笔记_26_操作符重载与转换(1)--可重载/不可重载的操作符.成员函数方式重载.友元函数方式重载 引言: 明智地使用操作符重载可以使类类型的使用像内置类型一样直观! 一.重载的操作符名 像任何其他函数一样,操作符重载函数有一个返回值和一个形参表.形参表必须具有操作符数目相同的形参.比如赋值时二元运算,所以该操作符函数有两个参数:第一个形参对应着左操作数,第二个形参对应右操作数. 大多数操作符可以定义为成员函数或非成员函数.当操作符为成员函数时,它的第一个操作数隐式绑定

C++ Primer 学习笔记_63_重载操作符与转换 --转换与类类型【上】

重载操作符与转换 --转换与类类型[上] 引言: 在前面我们提到过:可以用一个实参调用的非explicit构造函数定义一个隐式转换.当提供了实参类型的对象需要一个类类型的对象时,编译器将使用该转换.于是:这种构造函数定义了到类类型的转换. 除了定义到类类型的转换之外,还可以定义从类类型到其他类型的转换.即:我们可以定义转换操作符,给定类类型的对象,该操作符将产生其他类型的对象.和其他转换一样,编译器将自动应用这个转换. 一.转换为什么有用? 定义一个SmallInt的类,该类实现安全小整数,这个

C++ Primer 学习笔记_64_重载操作符与转换 --转换与类类型【下】

重载操作符与转换 --转换与类类型[下] 四.重载确定和类的实参 在需要转换函数的实参时,编译器自动应用类的转换操作符或构造函数.因此,应该在函数确定期间考虑类转换操作符.函数重载确定由三步组成: 1)确定候选函数集合:这些是与被调用函数同名的函数. 2)选择可行的函数:这些是形参数目和类型与函数调用中的实参相匹配的候选函数.选择可行函数时,如果有转换操作,编译器还要确定需要哪个转换操作来匹配每个形参. 3)选择最佳匹配的函数.为了确定最佳匹配,对将实参转换为对应形参所需的类型转换进行分类.对于