关闭

王老师 C++ 运算符重载 转换函数 第二讲

2736人阅读 评论(0) 收藏 举报

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节。

当“++”和“--”应用于基本数据类型时,前置版本和后置版本在效率上没有多大差别。当用于用户自定义的类型,尤其时大对象时,前置版本的效率要比后置版本高很多。后置版本总是要创建用一个临时对象,在退出函数时还要销毁它,而且返回临时对象的值时还会调用其拷贝构造函数。

0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:890432次
    • 积分:15169
    • 等级:
    • 排名:第786名
    • 原创:419篇
    • 转载:222篇
    • 译文:0篇
    • 评论:80条
    最新评论
    Learning