C++ 操作符重载 (operator)
重载不能改变操作符的优先级
如果一个内建操作符是一元的,那么所有对它的重载仍是一元的。如果是二元的重载后也是二元的
下面看一个有代表性的例子::
头文件Complex.h:
#include
using namespace std;
class Complex {
public:
Complex();
Complex(double);
Complex(double,double);
void write() const;
Complex operator +(const Complex &) const;
Complex operator -(const Complex &) const;
Complex operator *(const Complex &) const;
Complex operator /(const Complex &) const;
private:
double real;
double imag;
};
Complex::Complex(){
real = imag = 0.0;
}
Complex::Complex(double re) {
real = re;
imag = 0.0;
};
Complex::Complex(double re,double im) {
real = re;
imag = im;
}
void Complex::write() const {
cout << real << " + " << imag << 'i';
};
Complex Complex::operator + (const Complex &u) const {
Complex v(real+u.real,imag+u.imag);
return v;
}
Complex Complex::operator - (const Complex &u) const {
Complex v(real-u.real,imag-u.imag);
return v;
}
Complex Complex::operator* (const Complex &u) const {
Complex v(real * u.real - imag * u.imag,real * u.imag + imag * u.real);
return v;
}
Complex Complex::operator / (const Complex &u) const {
double temp = u.real * u.real + u.imag * u.imag;
Complex v( (real * u.real + imag * u.imag ) / temp, ( imag * u.real - real * u.imag ) / temp);
return v;
}
测试文件:Complex.cpp和测试结果:
一个被重载的操作符,就是一个用户自定义的函数,只不过它可以享受操作符语法所带来的便利
除了内存管理操作符new、new[]、delete、delete[]之外,一个以顶层函数形式被重载的操作符必须在它的参数列表中包含一个类的对象
下标操作符[]、赋值操作符=、函数调用操作符()和指针操作符->必须以类成员函数的形式进行重载(这样可以保证第一个操作数是类的对象,不然9[x]、6.32=x,不被接受)
操作符(如%)要么以成员函数被重载,要么以顶层函数被重载。对于后者将至少带一个对象参数,这是因为操作符以顶层函数实现时,如果连一个参数都没有,那么对如下表达式 x % y 编译系统就不能区分%是内建的,还是用户的。如果操作符%是类成员函数,或是有一个类对象参数的顶层函数,编译系统就能够根据特定的上下文决定调用哪一个%操作符
顶层函数重载操作符,类名和域解析符都没有了,因为它不是一个类成员函数
被重载的操作符,要么是一个类成员函数,要么在它的参数列表中包含一个类成员!!
下标操作符[]和函数调用操作符()只能以成员函数的形式被重载,不能成为顶层函数!!
eg:
修正后:
在上面那种情况,如果想要第二个表达式成功的话,就需要定义一个顶层函数重载+了
有一点要明白,当定义顶层函数时,函数里面不能含有对象的私有成员操作,否则编译通不过,下面有三种方法可以解决:
1,将私有成员设计为public成员,但是这种方法违背了类的信息隐藏原则
2,在Complex中加入用于访问real和imag的公有成员函数,但是容易造成接口混淆
3,将操作符重载函数声明为类的friend,但是不符合面向对象原则,应少用,建议仅在操作符重载时使用
类的私有成员只能被该类的成员函数和该类的friend函数访问
类的保护成员只能被该类的或其派生类的成员函数和该类的friend函数访问
class C {
//....
friend int f();
//...
};
该声明赋予f访问C的私有和保护成员的权力,因为f不是成员函数,该声明可以放在C中的private、protected或public的任意部分,不受访问控制符的影响、限制
程序员可对操作符>>进行重载,以支持用户自定义数据类型。>>的第一个操作数是系统类的对象(如cin是系统类istream的对象),而这些重载函数时以类成员函数的形式实现的。
如果在对用户自定义的类型重载>>时,就必须对系统类的源代码进行修改,而这显然是非常不明智的做法,因此只能将>>重载函数设计为顶层函数
输入流对象总是以引用方式传递,这是因为系统为了接受输入数据,需要更新输入流对象的某些信息
如果被重载>>的函数中和类的私有数据或者保护数据打交道,则需要将重载操作符声明为friend
拷贝构造函数和赋值操作符(=),都是用来拷贝一个类的对象给另一个相同类型的对象。
拷贝构造函数将一个对象拷贝到另一个新的对象(因为拷贝-构造);赋值操作符将一个对象拷贝到另一个已经存在的对象
如果类的作者没有提供拷贝构造函数,也没有重载赋值操作符,编译器将会给这个类提供一个拷贝构造函数和一个赋值操作符。编译器提供的拷贝构造函数和赋值操作符的运转机制是:将源对象中的每个数据成员拷贝到目标对象相应的数据成员中
看例子:
如果类的作者定义了指针成员,且该指针指向一块动态分配的存储空间,就应该为这个类设计拷贝构造函数,并重载赋值操作符
注意不要返回临时变量,重载里面错综复杂,小心一点
下标操作符[]必须要以成员函数的形式进行重载!
class C { //可以修改对象
returntype & operator[] (paramtype);
};
或者:
class C { //不能修改对象
const returntypr & operator[] (paramtype) const;
};
例子:
头文件:test.h
测试文件和结果:
上面可以不提供const版本的重载,但是就不能处理非const的对象,所以,有时候要考虑这一点,加上const重载!
函数调用操作符()必须要以成员函数的形式重载。
class C {
returntype operator()(paramtypes);
};
看例子:
头文件inttwoarray.h
#include
#include
using namespace std;
class intTwoArray {
public:
int & operator()(int,int);
const int & operator() (int,int) const;
intTwoArray(int,int);
int get_size1() const { return size1; }
int get_size2() const { return size2; }
private:
int size1;
int size2;
int *a;
};
int & intTwoArray::operator() (int i,int j) {
if( i < 0 || i >= size1 )
throw string("FirstOutOfBounds");
if( j < 0 || j >= size2 )
throw string("SecondOutOfBounds");
return a[i * size2 + j];
}
const int & intTwoArray::operator() (int i,int j) const {
if(i < 0 || i >= size1)
throw string("FirstOutOfBounds");
if(j < 0 || j >= size2)
throw string("SecondOutOfBounds");
return a[i * size2 + j];
}
intTwoArray::intTwoArray(int s1,int s2) {
int size = s1 * s2;
try{
a = new int[size];
}
catch(bad_alloc) {
cerr << "Can't allocate storage for intTwoArray\n";
throw;
}
size1 = s1;
size2 = s2;
}
测试程序和结果:
自增,自减也可以重载,但是前置,后置一共四种,前后置通过一个int参数区分,但是这个参数没有什么实际用途,仅仅起到区分的作用
例子:
头文件clock.h (需要注意一点,这个地方注意注释部分中间的代码,一定要加上否则。。。。。)
#include
#include
using namespace std;
/
class Entry;
class Dict;
ostream & operator<<(ostream &,const Entry &);
ostream & operator<<(ostream &,const Dict &);
class Entry {
public:
Entry() {flag = false;}
void add(const string &,const string &);
bool match(const string &) const;
void operator=(const string &);
void operator=(const char *);
friend ostream & operator<<(ostream &,const Entry &);
bool valid() const { return flag; }
void del() { flag = false; }
private:
string word;
string def;
bool flag;
};
void Entry::operator=(const string &str) {
def = str;
flag = true;
}
void Entry::operator=(const char * str) {
def = str;
flag = true;
}
ostream & operator<<(ostream &out,const Entry &e) {
out << e.word << " defined as: " << e.def ;
return out;
}
void Entry::add(const string &w,const string &d) {
word = w;
def = d;
}
bool Entry::match(const string &key) const {
return key == word;
}
enum {MaxEntries = 100};
class Dict {
public:
friend ostream & operator<<(ostream &,const Dict &);
void remove(const string &w);
Entry & operator[] (const string &);
Entry & operator[] (const char *);
private:
Entry entries[MaxEntries+1];
};
ostream & operator<<(ostream &out,const Dict &d) {
for(int i = 0 ;i < MaxEntries; i++)
if(d.entries[i].valid())
out << d.entries[i] << endl;
return out;
}
Entry &Dict::operator[](const string &k) { //返回引用是该程序的技巧。因为程序通过这个地方,和前面重载的=操作符填充字典返回因为是为了修改对应的值,即赋值
for(int i = 0; i < MaxEntries && entries[i].valid(); i ++)
if(entries[i].match(k))
return entries[i];
string not_found = "***not in dictionary";
entries[i].add(k,not_found);
return entries[i];
}
Entry & Dict::operator[](const char *k) {
string s = k;
return operator[](s);
}
void Dict::remove(const string &w)
{
int i,j;
for(i = 0 ;i< MaxEntries; i ++)
if(entries[i].valid() && entries[i].match(w))
break;
if(i == MaxEntries)
return ;
for(j = i + 1; j < MaxEntries && entries[j].valid() ; j++)
entries[j-1] = entries[j];
entries[j-1].del(); //最后一个失灵,即最后一个标志位设置为false,因为已经移到前面了
}
测试程序和结果:
内存管理操作符new、new[]、delete和delete[]既可以用成员函数也可以用顶层函数重载
嵌入式内存有限,应用程序经常需要直接管理内存
new操作符重载:
void * C::operator new(size_t size) {
//...
}
和
void * operator new(size_t size) {
//...
}
返回值void *
new和new[]操作符重载函数的第一个参数必须是size_t类型,其数值等于被创建对象大小,其他参数是可选的
delete操作符重载:
void C::operator delete( void * objPtr) {
//...
}
和
void operator delete(void *objPtr) {
//...
}
delete和delete[]操作符重载函数的第一个参数必须是void*类型,返回值必须是void,而其他参数则是可选的
看例子:
头文件frame.h:
#include
#include
using namespace std;
const int MaxFrames = 4;
const int DataSize = 128;
class Frame {
public:
Frame() { name = "NoName"; print(); }
Frame(const char *n) { name = n; print(); }
Frame(const string &n) { name = n ; print(); }
Frame(const string&,const void *,unsigned);
void print() const;
void *operator new(size_t);
void delete(void *);
private:
string name;
unsigned char data[DataSize];
};
Frame * allFrames = 0;
unsigned char framePool[MaxFrames * sizeof(Frame)];
bool alloc[MaxFrames];
Frame::Frame(const string &n,const void *d, unsigned bsize) {
name = n;
memcpy(data,d,bsize);
print();
}
void Frame::print() const {
cout << name << " created.\n";
}
void * Frame::operator new(size_t size) {
if(size != sizeof(Frame))
throw string("Not a Frame");
if(allFrames == 0) {
allFrames = reinterpret_cast
C++ 操作符重载 (operator)的更多相关文章
- 操作符重载operator
发现一篇好文: 转载: http://www.cnblogs.com/xiehongfeng100/p/4040858.html #include <iostream>#include & ...
- C++ 类型转换操作与操作符重载 operator type() 与 type operator()
类型转换操作符(type conversion operator)是一种特殊的类成员函数,它定义将类类型值转变为其他类型值的转换.转换操作符在类定义体内声明,在保留字 operator 之后跟着转换的 ...
- 15.C++-操作符重载
首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...
- 15.C++-操作符重载、并实现复数类
首先回忆下以前学的函数重载 函数重载 函数重载的本质为相互独立的不同函数 通过函数名和函数参数来确定函数调用 无法直接通过函数名得到重载函数的入口地址 函数重载必然发生在同一个作用域中 类中的函数重载 ...
- [置顶] operator overloading(操作符重载,运算符重载)运算符重载,浅拷贝(logical copy) ,vs, 深拷贝(physical copy)
operator overloading(操作符重载,运算符重载) 所谓重载就是重新赋予新的意义,之前我们已经学过函数重载,函数重载的要求是函数名相同,函数的参数列表不同(个数或者参数类型).操作符重 ...
- C++ operator overload -- 操作符重载
C++ operator overload -- 操作符重载 2011-12-13 14:18:29 分类: C/C++ 操作符重载有两种方式,一是以成员函数方式重载,另一种是全局函数. 先看例子 # ...
- C++的重载操作符(operator)介绍(转)
本文主要介绍C++中的重载操作符(operator)的相关知识. 1. 概述 1.1 what operator 是C++的一个关键字,它和运算符(如=)一起使用,表示一个运算符重载函数,在理解时可将 ...
- C++操作符重载总结operator(小结 更新ing)
操作符重载一个原则是:被操作的数据类型中 至少有一个是自定义的类型(使用class定义类),如果被操作的变量都是基本类型,那么就不能定义操作符重载. 1.如果重载了new,则必须重载delete,因为 ...
- C++ 友元(friend关键字)、类中的重载、操作符重载(operator关键字)
C++ 中友元的用法: 1.在类中使用friend关键字声明 2.类的友元可以是其它类或者具体函数 3.友元不是类的一部分 4.友元不受类中访问级别的限制 5.友元可以直接访问具体类中的所有成员. 友 ...
随机推荐
- [网页游戏开发]进一步了解Morn UI及工作流
Morn UI工作流 Morn Builder不仅仅是对Flash IDE的改进,传统的开发协作是以fla为基础,由于fla是二进制文件,在以svn等版本控制软件协作下,合并过程中会出现各种各样的问题 ...
- 深入浅出 - Android系统移植与平台开发(九)- Android系统system_server及Home启动
3.3 Zygote守护进程与system_server进程 Android的执行环境和Java执行环境有着本质的差别,在Android系统中每一个应用程序都是一独立的进程,当一个进程死掉时,不会影响 ...
- thinkphp Class 'PDO' not found 错误
thinkphp Class 'PDO' not found 错误,原因mysql5.7.26缺少pdo驱动,需要安装php的pdo和pdo_mysql扩展 本文以centOS为例 1.进入PHP源码 ...
- 序列化模块 json pickel shelve
一.json 模块 1.定义 将字典.列表等内容转换成字符串的过程就是序列化. 操作的数据类型有限,但是可以支持所有编程语言操作. 2.为什么要有序列化? 1.以某种存储形式使自定义对象持久化. 2 ...
- curl请求接口返回false,错误码60
我讲一下我遇到的这个问题,是因为最近服务器加了https导致的,网上找到了答案,加上这句 curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); 就可以正常返 ...
- poj 1325 Machine Schedule 解题报告
题目链接:http://poj.org/problem?id=1325 题目意思:有 k 个作业,机器A有 n 个模式:0 ~ n-1,机器B 有 m 个模式:0~ m-1.每一个作业能运行在 A 的 ...
- codeforces 673A A. Bear and Game(水题)
题目链接: A. Bear and Game time limit per test 2 seconds memory limit per test 256 megabytes input stand ...
- Centos Missing Library: QtWebKit.so.4
/******************************************************************** * Centos Missing Library: QtWe ...
- 并不对劲的bzoj1758:p4292:[WC2010]重建计划
题目大意 \(n\)(\(n\leq10^5\))个点的一棵树,有边权\(w\),给定\(l,r\),求边数在\([l,r]\)中的路径的平均边权的最大值 题解 二分答案,判断时将边权变成\(w-mi ...
- 「网络流24题」「LuoguP4014」 分配问题
Description 有 n 件工作要分配给 n 个人做.第 i 个人做第 j 件工作产生的效益为 cij.试设计一个将 n 件工作分配给 n 个人做的分配方案,使产生的总效益最大. Input 文 ...