《第一讲》
运算符函数:operator 运算符
运算符重载,两种方式:
a.成为成员函数
b.名字空间函数(友元函数)
不能重载的运算符有: ::, ., .*, ?:
必须重载为成员函数的运算符: [], (), ->, =
要求:
a.不能引进新运算符
b.不改变元数,优先级,结合性。
定义语法:
二元函数
值类型 operatoe◎(类型名 形参名) 函数体 // 成员函数
值类型 operatoe◎(类型名 形参名, 类型名 形参名) 函数体 // 全局函数
一元函数
值类型 operatoe◎() 函数体 // 成员函数
值类型 operatoe◎(类型名 形参名) 函数体 // 全局函数
例子程序:
#include <iostream>
using namespace std;
class com{
private:
int real;
int img;
public:
com(int real = 0, int img = 0){
this->real = real;
this->img = img;
}
void com_add(com &x, com &y, com &z){
z.real = x.real + y.real;
z.img = x.img + y.img;
}
com operator + (com x){
return com(this->real + x.real, this->img + x.img);
}
/*
com operator + (com & x){
return com(this->real + x.real, this->img + x.img);
}
*/
/*
//warning C4172: returning address of local variable or temporary
com & operator + (com & x){
return com(this->real + x.real, this->img + x.img);
}
*/
com operator + (int x){
return com(this->real + x, this->img);
}
friend com operator + (int x, com y);
void show(){
cout << real << "," << img << endl;
}
};
com operator +(int x, com y){
return com(x + y.real, y.img);
}
int main()
{
com a, b(1, 2), c(2, 3);
a = b + c;
a.show();
a.com_add(b, c, a);
a.show();
a = b + 3;
a.show();
a = 3 + c;
a.show();
}
注意:com & operator + (com & x)
在类成员函数中重载运算符是不允许返回引用的,会出现“返回局部变量的地址”警告。
但是对于函数 void com_add(com &x, com &y, com &z)则可以。
《第二讲》
1.赋值函数的重载
示例程序代码如下
#include "stdafx.h"
#include <malloc.h>
class stack
{
private:
int *sp, top, max;
void inflate();
public:
stack(int size = 10)
{
sp = (int *)malloc(sizeof(int) * size);
max = size;
top = 0;
}
int pop();
void push(int value);
stack & operator=(stack & rightValue);
};
//栈的容量增倍
void stack::inflate()
{
int index, *tp;
tp = (int *)malloc(sizeof(int) * max * 2);
for(index = 0; index < top; index++)
{
tp[index] = sp[index];
}
max += max;
free(sp);
sp = tp;
}
//出栈
int stack::pop()
{
if(top <= 0)
throw 1;
return sp[--top];
}
//入栈
void stack::push(int value)
{
if(top == max)
inflate();
sp[top++] = value;
}
//赋值函数
stack & stack::operator=(stack & rightValue)
{
top = rightValue.top;
max = rightValue.max;
sp = (int *)malloc(sizeof(int) * max);
for(int index = 0; index < max; index++)
{
sp[index] = rightValue.sp[index];
}
return *this;
}
void main()
{
stack x(100), y, z;
z = y = x;
}
这里要注意的是赋值函数的返回值是stack &,这是为了实现链式表达式,如z = y = x;。
这一点可见《高质量c/c++编程》(林锐)一书。
2.[]的重载
语法:值类型 operator[](一个形参) 函数体
示例程序如下:
#include "stdafx.h"
#include <malloc.h>
#include <iostream>
using namespace std;
class Array
{
private:
int *a, len;
void inflate()
{
cout << "the array is inflating..." << endl;
int *b = (int *)malloc(sizeof(int) * len * 2);
for(int i = 0; i < len; i++)
{
b[i] = a[i];
}
len += len;
free(a);
a = b;
}
public:
Array(int size):len(size)
{
a = (int *)malloc(sizeof(int) * size);
}
int & operator[](int index)
{
if(index < 0)
throw 1;
if(index >= len)
inflate();
return a[index];
}
void trans()
{
for(int i = 0; i < len; i++)
{
cout << a[i] << endl;
}
}
};
void main()
{
Array a(15);
for(int i = 0; i < 20; i ++)
{
a[i] = i;
}
a.trans();
}
3.()的重载
示例程序代码:
#include "stdafx.h"
#include <stdlib.h>
#include <time.h>
#include <iostream>
using namespace std;
//求最小值
template <typename T1, typename T2> T1 &min(T1 *x, int n, T2 cmp)
{
int j = 0;
for(int i = 1; i < n; i++)
{
if(cmp(x[i], x[j]))
{
j = i;
}
}
return x[j];
}
//函数对象
class Fun_obj
{
public:
bool operator()(int x, int y)
{
return x < y;
}
};
int cmp(int x, int y)
{
return x < y;
}
void main()
{
int a[] = {0, 1, 7, 9, 5, 4, -2, 3};
int len = sizeof(a)/sizeof(int);
Fun_obj fo;
//cout << "min by function_object:" <<
// min(a, sizeof(a)/sizeof(int), fo) << endl;
//cout << "min by function_pointer:" <<
// min(a, sizeof(a)/sizeof(int), cmp) << endl;
long num = 100000000;
clock_t start, finish;
double duration;
start = clock();
for(int i = 0; i < num; i++)
min(a, len, fo);
finish = clock();
duration = (double)(finish - start); // / CLOCKS_PER_SEC;
cout << "min by function_object :" <<
duration << " seconds" << endl;
start = clock();
for(int i = 0; i < num; i++)
min(a, len, cmp);
finish = clock();
duration = (double)(finish - start); // / CLOCKS_PER_SEC;
cout << "min by function_pointer :" <<
duration << " seconds" << endl;
}
函数对象只是重载了成员函数运算符(),而类成员函数均为inline函数,inline函数在编译时展开;使用函数指针指向的函数是有一个函数调用和函数返回的过程的,所以使用函数对象比使用一般的函数效率要高。
4.->的重载
语法:值类型 operator->() 函数体
返回值必须是(1)指针 或 (2)类类型的对象或者对象的引用
调用语法:object->member
执行过程:
(1)如果object是指针,所指对象需要有member成员;
(2)object是一个对象或对象引用,所属类必须重载->。计算->,得到obj(指针),做object = obj,转(1)。
例如:
#include "stdafx.h"
#include <iostream>
using namespace std;
class A
{
public:
int x;
A(int value):x(value)
{
}
A * operator->()
{
return this;
}
};
class B
{
A & a;
public:
B(A & value):a(value)
{
}
A & operator->()
{
return a;
}
};
void main()
{
A a(99);
B b(a);
cout << b->x << endl;
}
示例程序(二):
#include "stdafx.h"
#include <iostream>
using namespace std;
class Node
{
public:
int info;
Node * next;
Node(int value):info(value)
{
}
class iter
{
public:
Node *p, *q;
iter(Node * u)
{
p = u;
q = NULL;
}
iter()
{
p = q = NULL;
}
iter & operator++()
{
if(p != NULL)
q = p;
p = p->next;
return *this;
}
iter & operator++(int)
{
return operator++();
}
bool operator!=(iter i)
{
return p != i.p;
}
Node * operator->()
{
return p;
}
};
iter begin()
{
return iter(this);
}
iter end()
{
return iter();
}
void print()
{
iter p = begin();
iter q = end();
while(p != q)
{
cout << p->info << endl;
p++;
}
}
void insert(Node ** h)
{
iter i = (*h)->begin(), j = (*h)->end();
while(i != j && i->info < this->info)
i++;
this->next = i.p;
if(i.q == NULL)
*h = this;
else
i.q->next = this;
}
};
void main()
{
Node * head = NULL;
(new Node(2))->insert(&head);
(new Node(3))->insert(&head);
(new Node(1))->insert(&head);
(new Node(4))->insert(&head);
head->print();
}
这里需要注意的是,在C++程序中,重载“++”和“--”运算符正确理解它们的语义很重要。
int b = ++a;
语义:
a += 1;
int b = a;
而
int b = a++;
语义是:
int temp = a;
a += 1;
int b = temp;
temp.~int();
而不是
int b = a;
a += 1;
C+ +标准规定:当为一个类重载“++”和“--”的前置版本时,不需要参数;当为一个类重载后置版本时,需要一个int类型的参数作为标志(即哑元,非具名参数)。至于问什么是这样而不是通过一个特殊的关键字来标识这种位置关系,参考《The Design and Evolution of C++》11.5.3节。
当“++”和“--”应用于基本数据类型时,前置版本和后置版本在效率上没有多大差别。当用于用户自定义的类型,尤其时大对象时,前置版本的效率要比后置版本高很多。后置版本总是要创建用一个临时对象,在退出函数时还要销毁它,而且返回临时对象的值时还会调用其拷贝构造函数。
《第三讲》
示例程序:
(1)new
#include <stdafx.h>
#include <malloc.h>
#include <iostream>
using namespace std;
class com
{
public:
int real, image;
com(int x, int y)
{
this->real = x;
this->image = y;
}
};
void main()
{
com c(2, 3);
com *p, *q;
//在堆中分配空间
p = new com(2, 4);
//这两种方式都能动态创建一个对象
//但是下面的语句内存没有初始化
q = (com *)malloc(sizeof(com));
q->real = 2;
q->image = 4;
cout << "hehe" << endl;
//error C2512: 'com' : no appropriate default constructor available
new com[3];
}
(2)重载new delete
示例:在静态区申请动态对象
#include <stdafx.h>
#include <iostream>
using namespace std;
#define N 3
class Item
{
int info, mark;
public:
static Item static_Zone[N];
Item()
{
cout << this << endl;
mark = 0;
}
Item(int x)
{
this->info = x;
this->mark = 1;
}
~Item()
{
cout << "deconstructor is called!" << endl;
this->mark = 0;
}
void * operator new(size_t size) throw (int)
{
cout << "my new" << endl;
for(int i = 0; i < N; i++)
{
if(static_Zone[i].mark == 0)
{
cout << &static_Zone[i] << endl;
return &static_Zone[i];
}
}
throw 1;
}
void operator delete(void *p)
{
cout << "my delete" << endl;
if(p == NULL)
return ;
((Item *)p)->mark = 0;
}
};
Item Item::static_Zone[N];
void functiona()
{
Item *p, *q, *r, *s;
try
{
p = new Item(3);
q = new Item(4);
r = new Item(5);
s = new Item(6);
}catch(int)
{
cout << "memory leak!" << endl;
delete p;
s = new Item(6);
}
}
(3)析构函数和delete的区别
析构函数负责释放由构造函数申请的内存.
delete负责释放new动态申请的内存.