• c++学习笔记_4


    前言:本笔记所对应的课程为中国大学mooc中北京大学的程序设计与算法(三)C++面向对象程序设计,主要供自己复习使用,且本笔记建立在会使用c和java的基础上,只针对与c和java的不同来写

    运算符重载

    运算符重载的基本概念

    1. 目的:希望使对象也能用基本的运算符进行运算。本质上是函数重载。

    2. 可以将运算符重载为普通函数,也可以重载为成员函数。

    3. 一个运算符可以被多次重载,根据实参的具体类型决定调用哪个重载函数。

    4. 格式:

      返回值类型 operator运算符符号(参数表){

      }

    实例:

    class Complex{
        public:
            double real, imag;
            Complex(double r = 0.0, double i = 0.0):real(r), imag(i){
    
            }
            Complex operator-(const Complex & c);
    };
    Complex operator+(const Complex & c1, const Complex & c2){
        return Complex(c1.real+c2.real, c1.imag+c2.imag);
    } //当重载为普通函数时,参数个数为运算符目数
    Complex Complex::operator-(const Complex & c){
        return Complex(real-c.real, imag-c.imag);
    } //当重载为成员函数时,参数个数为运算符目数减一
    
    int main(){
        Complex a(4, 4), b(1, 1), c, d;
        c = a + b; //等价于 c = operator+(a, b);
        d = a - b; //等价于 d = a.operator-(b);
    }
    

    赋值运算符的重载

    赋值运算符只能重载为成员函数。

    实例:

    # include <iostream>
    # include <cstring>
    
    using namespace std;
    
    class String{
        private:
            char * str;
        public:
            String():str(new char[1]) { str = 0; }
            String(String & s){
                str = new char[strlen(s.str)+1];
                strcpy(str, s.str);
            }
    
            long long adderss() {
            	return (long long)(&str);
    		}
            const char * c_str() { return str; }
    
            String & operator=(const char * s);
            String & operator=(const String & s);
    
            ~String() { delete [] str; }
    };
    
    String & String::operator=(const char * s){
    
        //该函数的作用是可以使“obj = "hello"”这样的语句成立(和类型转换构造函数是有区别的)。
        delete [] str;
        str = new char[strlen(s)+1];
        strcpy(str, s);
        return * this;
    }
    
    String & String::operator=(const String & s){
    
        //这一句是防止出现 s = s 的情况。
        if(this == &s)
            return * this;
        delete [] str;
        str = new char[strlen(s.str)+1];
        strcpy(str, s.str);
        return * this;
    }
    
    int main(){
        String s;
        s = "good luck";
        cout << s.c_str() << endl;
    
        //等价于s.operator=("good luck");
    
        //String s2 = "hello";
        //这一句是错的,原因:这里的等号不是赋值号,而是“类型转换构造函数”的赋初值法,由于没有写“类型转换构造函数”,因此不会通过。
    
        String s3, s4;
        s3 = "first";
        s4 = "second";
        cout << s3.adderss() << endl;
    	cout << s4.adderss() << endl;
        s3 = s4; 
        cout << s3.adderss() << endl;
    	cout << s4.adderss() << endl;
        cout << s3.c_str() << endl;
    	cout << s4.c_str() << endl;
    
        //直接让同一类的两对象相等时,会让s3中每一成员变量的值去等于s4中对应的每一成员变量的值。由于String的成员变量str是指针,因此直接让s3 = s4的话会导致指向同一内存区域,后续进行其他操作时有很大隐患。因此要额外增加一赋值运算符重载函数。
        //这里的address()函数用以检查str的地址是否也被赋值
    
        String s5 = s;
        cout << s5.c_str() << endl;
    
        //注意这里的等号不是赋值号,而是调用“复制构造函数”赋初值。等价于"String s5(s); "。同理由于String的成员变量str是指针,如果使用默认的“复制构造函数”,会产生上述同样的问题,因此要额外写一个“复制构造函数”。
    
        return 0;
    }
    

    注意,对于operator=的返回值类型,应该是String &,而不是void或是String

    运算符重载为友元

    目的:我们一般将运算符重载为成员函数,但有时会出现不够用的情况,因此需要将运算符重载为友元。

    实例:

    class Complex{
        public:
            double real, imag;
            Complex(double r = 0.0, double i = 0.0):real(r), imag(i){ }
            Complex operator+(double r){
                return Complex(real + r, imag);
            } //(1)
            friend Complex operator+(double r, Complex & c); //(2)
    };
    
    Complex operator+(double r, Complex & c){
        return Complex(c.real + r, c.imag);
    }
    
    int main(){
        Complex c;
        c = c + 5; //调用(1)
        c = 5 + c; //调用(2)
    }
    

    可变长数组类的实现

    实现方法:重载[]运算符。具体代码暂略。

    流插入运算符和流提取运算符的重载

    1. cout是在iostream中定义的,ostream类的对象;cin是istream类的对象。
    2. 一般将重载函数设为全局函数,如果需要用到某对象中的private变量,则可以声明为friend

    实例:

    # include <iostream>
    
    using namespace std;
    
    class Student{
        private:
            int age;
            friend ostream & operator << (ostream & o, const Student & s);
        public:
            Student(int n):age(n) {};
    };
    
    ostream & operator << (ostream & o, const Student & s){
        o << s.age;
        return o;
    }
    
    int main(){
        Student s(5);
        cout << s << " years old" << endl;
        return 0;
    } 
    
    

    类型转换运算符的重载

    1. 注意强制类型转换函数的书写形式,不用写返回类型
    2. 在存在某强制类型转换函数的情况下,如果某些地方使用了该强制类型转换函数可以使程序正确运行,那么会发生隐式的强制类型转换。

    实例:

    # include <iostream>
    
    using namespace std;
    
    class Complex{
        private:
            double real, imag;
        public:
            Complex(double r, double i):real(r), imag(i) {}
            operator double (){
                return real;
            }
            //注意强制类型转换函数的书写形式 
    };
    
    int main(){
        Complex c(5, 4);
        cout << (double)c << endl; 
        double n = 2 + c; //这里会发生自动的强制类型转换,等价于n = 2 + c.operator double(); 
        cout << n << endl;
        return 0;
    }
    

    自增自减运算符的重载

    1. 由于自增自减运算符有前置与后置之分,因此两者写法不同:前置运算符需要作为一元运算符重载,后置运算符需要作为二元运算符重载(增加一个无用的int参数)具体用法如下面实例所示。
    2. 在只写了前置的重载函数,而没有写后置的重载函数时,如果调用后置运算(例如obj++),在vs中会调用前置重载,在dev中会编译出错。

    实例:

    # include <iostream>
    
    using namespace std;
    
    class Complex{
    	private:
    		double real, imag;
    	public:
    		Complex(double r, double i):real(r), imag(i){ };
    		
    		//前置成员函数写法:返回值为对象的引用 
    		Complex & operator ++ (){
    			++real; 
    			return *this;
    		}
    		//后置成员函数写法:多了一个无用的int参数,返回值为新的对象 
    		Complex operator ++ (int){
    			Complex temp(*this); 
    			++real;
    			return temp;
    		}
    		friend Complex & operator -- (Complex & c);
    		friend Complex operator -- (Complex & c, int); 
    		
    		friend ostream & operator << (ostream & o, const Complex & c);
    }; 
    
    //前置全局函数写法 
    Complex & operator -- (Complex & c){
    	--c.real;
    	return c;
    }
    
    //后置全局函数写法 
    Complex operator -- (Complex & c, int){
    	Complex temp(c);
    	--c.real;
    	return temp;
    }
    
    ostream & operator << (ostream & o, const Complex & c){
    	o << c.real;
    	return o;
    }
    
    int main(){
    	Complex d(5, 4);
    	
    	cout << (d++) << ",";
    	cout << d << ",";
    	cout << (++d) << ",";
    	cout << d << endl;
    	
    	cout << (d--) << ",";
    	cout << d << ",";
    	cout << (--d) << ",";
    	cout << d << endl;
    	
    	//输出结果应为:
    	//5,6,7,7
    	//7,6,5,5 
    	return 0;
    } 
    

    其他注意事项:

    1. c++不允许定义新的运算符。
    2. 重载后的运算符含义应符合日常习惯。
    3. 运算符重载不改变运算符的优先级。
    4. 一下运算符不可被重载: . .* :: ?: sizeof
    5. 重载运算符() [] -> =时,运算符重载函数必须声明为类的成员函数。
  • 相关阅读:
    Client-Side Template Injection with AngularJS
    502 BAD GATEWAY-k8s的cgroup限制了apache的可用内存
    alertmanager的web页面显示UTC时间的问题
    结构化数据
    天马行空 + 行业趋势
    elasticsearch备份脚本
    mongodb的安装部署-备份
    redis安装-备份-恢复 -- redislive -- web管理工具
    elasticsearch 的post put 方式的对比 setting mapping设置
    用elasticsearchdump备份恢复数据
  • 原文地址:https://www.cnblogs.com/fyunaru/p/11465875.html
Copyright © 2020-2023  润新知