首页 > 代码库 > 0718-----C++Primer听课笔记----------运算符重载
0718-----C++Primer听课笔记----------运算符重载
0.两个要点
a) 一个空类,编译器自动合成默认无参构造函数、析构函数、拷贝构造函数、赋值运算符。
b) 在编写类的时候,必须严格区分对象是否可复制。
1.运算符重载之 string类
1.1 运算符重载的几个要点:
a) 运算符重载可以有成员函数和友元函数的形式,后者比前者多一个参数。
b) =和+=必须重载为成员函数的形式(不太理解原因)。
c) 输入和输出必须为友元函数的形式。而且输入操作符要考虑输入失败的情况。
d) 运算符重载为成员函数的形式,那么该操作符的第一个操作数必然为该类的对象。以+=为例,s += “hello” 那么等价于 s.operator+=(“hello”)。
1.2 String 类源码
#ifndef __STRING_H__#define __STRING_H__#include <stddef.h>#include <iostream>#include <string.h>class String{ friend std::ostream &operator<<(std::ostream &, const String &); friend std::istream &operator>>(std::istream &, String &); friend String operator+(const String &, const String &); friend String operator+(const String &, const char *); friend String operator+(const char *, const String &);// friend String &operator+(const char*, const char*); friend bool operator==(const String &, const String &); friend bool operator!=(const String &, const String &); friend bool operator>(const String &, const String &); friend bool operator<(const String &, const String &); friend bool operator>=(const String &, const String &); friend bool operator<=(const String &, const String &); public: String(); String(const char* str); String(const String &other); ~String(); String &operator= (const String &other); String &operator= (const char *str); String &operator+= (const String &other); String &operator+= (const char *str); char &operator[](size_t index); char &operator[](size_t index) const; size_t size() const; void debug() const; private: char *str_;};inline std::ostream &operator<<(std::ostream &os, const String &s){ return os << s.str_; //将换行权交给调用者}inline std::istream &operator>>(std::istream &is, String &s){ char buf[1024]; is >> buf; if(is){ //输入失败时不改变原对象 s.str_ = buf; } return is;}inline String operator+(const String &s1, const String &s2){ String ret(s1); //加法不改变原对象 ret += s2; return ret;}inline String operator+(const String &s1, const char *s2){ return s1 + String(s2);}inline String operator+(const char *s1, const String &s2){ return String(s1) + s2;}inline bool operator==(const String &s1, const String &s2){ return ::strcmp(s1.str_, s2.str_) == 0;}inline bool operator!=(const String &s1, const String &s2){ return !(s1 == s2);}inline bool operator>(const String &s1, const String &s2){ return ::strcmp(s1.str_, s2.str_) > 0;}inline bool operator<(const String &s1, const String &s2){ return s2 > s1;}inline bool operator>=(const String &s1, const String &s2){ return !(s1 < s2);}inline bool operator<=(const String &s1, const String &s2){ return !(s1 > s2);}#endif#include "string.h"#include <iostream>#include <string.h>String::String() :str_ (new char[1]){ str_[0] = 0;}String::String(const char* str) :str_(new char[::strlen(str) + 1]){ ::strcpy(str_, str);}String::String(const String &other) :str_(new char[::strlen(other.str_) + 1]){ :: strcpy(str_, other.str_);}String::~String(){ delete[] str_;}String& String::operator=(const String &other){ if(&other != this){ delete[] str_; str_ = new char[::strlen(other.str_) + 1]; ::strcpy(str_, other.str_); } return *this;}String &String::operator=(const char *str){ return operator=(String(str));}String &String::operator+=(const String &other){ char *ret = new char[size() + other.size() + 1]; ret = str_; ::strcat(ret, other.str_); str_ = ret; return *this;}String &String::operator+=(const char *str){ return operator+=(String(str));}char &String::operator[](size_t index){ return str_[index];}char &String::operator[](size_t index) const{ return str_[index];}size_t String::size() const{ return ::strlen(str_);}void String::debug()const{ std::cout << str_ << std::endl;}#include "string.h"#include <iostream>using namespace std;int main(int argc, const char *argv[]){ String s1("apple"); // cout << s1 << endl; String s3; s3 = "hello"; //cout << "world " + s3 << endl; cout << (s1 == s3) << endl; cout << (s1 > s3) <<endl; cout << (s1 >= s3) << endl; return 0;}
2. 自增运算符的重载
2.1 以整形 Integer 类为例,来重载前缀自增运算符(++i)和 后缀自增运算符(i++),这里要注意的几点:
a) 为了区别两个函数,我们将前缀自增运算符的重载函数中增加一个无用的参数。
b) 重载输出操作符的第二个参数 必须是 const, 因为在调用 i++ 时,函数返回值采用值传递,生成了临时对象,注意临时对象是不能修改的 具有const语义,因而此处必须设为const;对于++i 操作 ,该函数返回当前对象的引用,因而是否为const不影响。因此要记住,重载输出操作符时,第二个参数都设为const 引用,这里第一个参数也必须是引用,因为流对象不能复制和赋值。
c) 在生成临时对象的时候调用了拷贝构造函数。
d) Integer(int data)类型的构造函数,具有一种转化语义,能够将int转化为Integer,而加上explicit就禁用掉了转化语义。加上该关键字后,只能采用原生的构造方式如Integer t(100),而不能使用转化形式Integer t = 33。
e)自增操作符,前置和后置的区别:前置直接修改原对象,直接返回; 后置需要暂存之前的结果,修改对象后,将旧的对象返回。
2.2 源码
#ifndef __INTEGER_H__#define __INTEGER_H__#include <iostream>class Integer{ friend std::ostream &operator<<(std::ostream &os, const Integer &itg); public: Integer(); explicit Integer(int data); Integer(const Integer &other); ~Integer(); Integer &operator=(const Integer &i); /* * 为了区别前缀和后缀式 传入一个无用的形参 */ Integer &operator++(); Integer operator++(int); private: int data_;};inline std::ostream &operator<<(std::ostream &os, const Integer &itg){ return os << itg.data_;}#endif#include "integer.h"Integer::Integer() :data_(0){}Integer::Integer(int data) :data_(data){}Integer::Integer(const Integer &other) :data_(other.data_){ std::cout << "call copy construction" << std::endl;}Integer::~Integer(){}Integer &Integer::operator=(const Integer &i){ data_ = i.data_; return *this;}Integer &Integer::operator++(){ std::cout << "call prefix " << std::endl; data_++; return *this;}Integer Integer::operator++(int){//此处的 int无用 因此不用命名 std::cout << "call postfix" << std::endl; Integer ret(*this); data_++; return ret; //这里函数返回时 生成了临时对象;}#include <iostream>#include "integer.h"using namespace std;int main(int argc, const char *argv[]){ Integer itg(10); cout << itg << endl; cout << ++itg << endl; Integer itg2(20); cout << itg2 << endl; cout << itg2++ << endl;/* * 构造函数加上 explicit 之后 * 再使用这种隐身转换就会报错 Integer itg3 = 8; cout << itg3 << endl;*/ return 0;}