前言:本笔记所对应的课程为中国大学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. 重载运算符() [] -> =时,运算符重载函数必须声明为类的成员函数。

c++学习笔记_4的更多相关文章

  1. servlet学习笔记_4

    一.response.1.response.characterEncoding和response.setContentType("text/html;charset=UTF-8") ...

  2. Java编程思想学习笔记_4(异常机制,容器)

    一.finally语句注意的细节: 当涉及到break和continue语句的时候,finally字句也会得到执行. public class Test7 { public static void m ...

  3. PythonI/O进阶学习笔记_4.自定义序列类(序列基类继承关系/可切片对象/推导式)

    前言: 本文代码基于python3 Content: 1.python中的序列类分类 2. python序列中abc基类继承关系 3. 由list的extend等方法来看序列类的一些特定方法 4. l ...

  4. Flink学习笔记:Flink API 通用基本概念

    本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKhaz ...

  5. flink学习笔记-各种Time

    说明:本文为<Flink大数据项目实战>学习笔记,想通过视频系统学习Flink这个最火爆的大数据计算框架的同学,推荐学习课程: Flink大数据项目实战:http://t.cn/EJtKh ...

  6. matlab学习笔记8 基本绘图命令-LineSpec线条设定

    一起来学matlab-matlab学习笔记8 基本绘图命令_4 LineSpec线条设定 觉得有用的话,欢迎一起讨论相互学习~Follow Me 绘图函数接受线条设定作为参数并相应地修改生成的图形.您 ...

  7. matlab学习笔记4--导入和导出Internet数据

    一起来学matlab-matlab学习笔记4 数据导入和导出_4 导入和导出Internet数据 觉得有用的话,欢迎一起讨论相互学习~Follow Me 参考书籍 <matlab 程序设计与综合 ...

  8. Learning hard 学习笔记

    第一章 你真的了解C#吗 1.什么是C#, 微软公司,面向对象,运行于.NET Framework之上, 2.C#能编写哪些应用程序, Windows应用桌面程序,Web应用程序,Web服务, 3.什 ...

  9. js学习笔记:webpack基础入门(一)

    之前听说过webpack,今天想正式的接触一下,先跟着webpack的官方用户指南走: 在这里有: 如何安装webpack 如何使用webpack 如何使用loader 如何使用webpack的开发者 ...

随机推荐

  1. web前端开发-博客目录

    web前端开发是一个新的领域,知识连接范围广,处于设计与后端数据交互的桥梁,并且现在很多web前端相关语言标准,框架库都在高速发展.在学习过程中也常常处于烦躁与迷茫,有时候一直在想如何能够使自己更加系 ...

  2. JSP第一章动态网页的基础

    什么是动态网站(dynamic website)? 动态网站: 误区:初学者一般认为动态网页,就是会动的网页,但实际上不是这样的. 动态网页是指在服务器端运行的,使用程序语言设计的交互式网页,它们会根 ...

  3. Win常用软件

    本节只适合windows系统 VScode 下载 安装 双击安装 打开目录方式 右键文件夹->使用VSCode打开 命令行打开 code folder [dzlua@win10:~]$ ls a ...

  4. 【Python3爬虫】当爬虫碰到表单提交,有点意思

    一.写在前面 我写爬虫已经写了一段时间了,对于那些使用GET请求或者POST请求的网页,爬取的时候都还算得心应手.不过最近遇到了一个有趣的网站,虽然爬取的难度不大,不过因为表单提交的存在,所以一开始还 ...

  5. Intellij IDEA 中 使用 Git

    前一段时间使用 Microsoft 的 Visual Studio Code 中使用 Git 对前端项目进行项目代码的开发提交. 使用后感觉挺好的,用的多了也觉得挺简单方便的. 现在需要在 Intel ...

  6. .Net集合详解

    前言 前面几篇文章讲了泛型.讲了数组,都有提到集合,这一节重点对集合进行详细解说.本文主要使用各种集合类型.以至于评估其性能,针对不同的场景选择不同的集合使用. 集合分类详解 一.列表 列表的创建 v ...

  7. 认识 tomcat 被占用问题

    (1) Server 中的 port 该端口为tomcat使用jvm的端口,必须保证唯一性,否则tomcat启动不成功: (2) Connector 中的 port 该端口为tomcat中所有web应 ...

  8. codeforces 576 div2 A-D题解

    A题 Description 题目链接: https://codeforces.com/contest/1199/problem/A 题意: 给定长度为n(1≤n≤100000)的一个序列a,以及两个 ...

  9. JVM运行时数据区--深入理解Java虚拟机 读后感

    程序计数器 程序计数器是线程私有的区域,很好理解嘛~,每个线程当然得有个计数器记录当前执行到那个指令.占用的内存空间小,可以把它看成是当前线程所执行的字节码的行号指示器.如果线程在执行Java方法,这 ...

  10. 使用Graphlab参加Kaggle比赛(2017-08-20 发布于知乎)

    之前用学生证在graphlab上申了一年的graphlab使用权(华盛顿大学机器学习课程需要)然后今天突然想到完全可以用这个东东来参加kaggle. 下午参考了一篇教程,把notebook上面的写好了 ...