C++数据抽象——对象与类详解

数据抽象——对象与类

C++对象与类自学笔记,以课本为基础,加了一点自己的改进,并附有相关代码。发布在博客上作为记录,并且勉励自己!

1.用类定义栈

#include<iostream>
using namespace std;
class MyStack
{
public:
	MyStack()
	{ 
		mytop = NULL;
		len = 0;
	}//构造函数
	void push(int i);
	void pop();
	int top();
	bool isempty();
	int size();
	void swap(MyStack &target);
private:
	struct Node
	{
		int content;
		Node* next;
	}*mytop;

	int len;
};
void MyStack::push(int i)
{
	Node* p = new Node;
	if (p == NULL)
	{
		cerr << "Stack is empty.\n";
		exit(-1);
	}
	else
	{
		p->content = i;
		p->next = mytop;
		mytop = p;
		this->len++;
		return;
	}
}
void MyStack::pop()
{
	if (mytop == NULL)
	{
		cerr << "Stack is empty.\n";
		exit(-1);
	}
	else
	{
		Node* p = mytop;
		mytop = mytop->next;
		delete p;
		this->len--;
		return;
	}
}
int MyStack::top()
{
	if (this->mytop == NULL)
	{
		cerr << "Stack is empty.\n";
		exit(-1);
	}
	else
		return this->mytop->content;
}
bool MyStack::isempty()
{
	if (this->mytop == NULL)
		return 1;
	else
		return 0;
}
int MyStack::size()
{
	return this->len;
}

void MyStack::swap(MyStack& target)
{
	MyStack st1, st2;
	while (!this->isempty())
	{
		st1.push(this->mytop->content);
		this->pop();
	}
	while (!target.isempty())
	{
		st2.push(target.mytop->content);
		target.pop();
	}

	while (!st2.isempty())
	{
		this->push(st2.mytop->content);
		st2.pop();
	}
	while (!st1.isempty())
	{
		target.push(st1.mytop->content);
		st1.pop();
	}

	return;
}
int main()
{
	//调试代码
	MyStack st1, st2;
	if (st1.isempty())
		cout << "st1 is empty." << endl;
	if (st2.isempty())
		cout << "st2 is empty." << endl;
	for (int i = 0; i < 4; i++)
		st1.push(i);
	for (int i = 4; i < 8; i++)
		st2.push(i);
	cout << "Size of st1 is:" << st1.size() << endl;
	cout << "Size of st2 is:" << st2.size() << endl;
	
	cout << "Before swaping, the top of st1 is " << st1.top() << endl;
	cout << "Before swaping, the top of st2 is " << st2.top() << endl;

	st1.swap(st2);
	cout << "After swaping, the top of st1 is " << st1.top() << endl;
	cout << "After swaping, the top of st2 is " << st2.top() << endl;
	
}

2.构造函数

#include<iostream>
using namespace std;
class A
{
public:
	A() { cout << "默认构造函数\n"; };//无参数或者参数全为默认值
	A(int i){cout << "参数为int的构造函数\n"; }
	A(char *p) { cout << "参数为char *p的构造函数\n"; }
};

int main()
{
	A a1;//可以写成A a1=A();
	A a2(1);//可以写成A a2=A(1);或A a2=1;
	char p[]="abcd";
	A a3(p);//不知为何不能写成 A a3("abcd");
	A a[4];//调用对象a[0]~a[3]的默认构造函数
	A b[5] = { A(),A(1),A(p),2,p };
}

3.成员初始化表

#include<iostream>
using namespace std;
class A
{
	int x;
	const int y;
	int& z;
public:
	A() :z(x), y(1)
	{
		x = 0;
	}
	//or
	/*
	A() :x(0),z(x),y(1)
	{
	}
	*/
public:
	void Print()
	{
		cout << "x初始化的值为" << this->x << endl;
		cout << "z初始化指向x,z指向的值为" << this->z << endl;
		cout << "常量y的值为" << this->y << endl;
	}
};
int main()
{
	A a;
	a.Print();
}

4.析构函数

//名称:~A()
//基于数据抽象与封装思想定义一个类来描述字符串
#include<cstring>
#include<cstdlib>
#include<iostream>
using namespace std;
class String
{
private:
	char* str;
public:
	String()
	{
		str = NULL;
	}
	String(const char* p)
	{
		str = new char[strlen(p) + 1];
		strcpy(str, p);
	}
	~String()
	{
		delete []str;
		str = NULL;
	}
	String(const String& s)//显式定义拷贝构造函数
	{
		str = new char[strlen(s.str) + 1];
		strcpy(str, s.str);
	}
	int length() { return strlen(str); }
	char& char_at(int i)
	{
		if (i < 0 || i >= strlen(str))
		{
			cerr << "超出字符串范围!\n";
			exit(-1);
		}
		return str[i];
	} 
	const char* get_str()//返回字符串指针
	{
		return str;
	}
	//下面两个重载函数实现字符串复制功能
	String& copy(const char* p)
	{
		delete[]str;//归还原来的资源
		str = new char[strlen(p) + 1];//申请新资源
		strcpy(str, p);
		return *this;
	}
	String& copy(const String& s) { return copy(s.str); }
	//下面两个重载函数实现字符串拼接功能
	String& append(const char* p)
	{
		char* p1 = new char[strlen(str) + strlen(p) + 1];
		strcpy(p1, str);
		strcat(p1, p);
		delete[]str;
		str = p1;
		return*this;
	}
	String& append(const String& s) { return append(s.str); }

	//下面两个重载函数实现字符串比较功能
	int compare(const char* p) { return strcmp(str, p); }
	int compare(const String& s) { return strcmp(str, s.str); }

};
int main()
{
	String s1;
	String s2("abcdefg");
	s1.copy("xyz");
	s2.append(s1);
	for (int i = 0; i < s2.length(); i++)//把s2中的小写字母变成大写字母
	{
		if (s2.char_at(i) >= 'a' && s2.char_at(i) <= 'z')
			s2.char_at(i) = s2.char_at(i) - 'a' + 'A';
	}
	if (s2.compare("ABCDEFGXYZ") == 0)cout << "OK\n";
	cout << s1.get_str() << endl << s2.get_str() << endl;
	return 0;
}

5.成员对象初始化

#include<iostream>
using namespace std;
class A
{
	int m;
public:
	A() { m = 0; }
	A(int m1) { m = m1; }
	int get_m()
	{
		return m;
	}
};
class B
{
	int n;
	A a;
public:
	B() { n = 0; }
	B(int n1) { n = n1; }
	B(int n1, int m1) :a(m1) { n = n1; }
public:
	int get_n()
	{
		return this->n;
	}
	int get_am()
	{
		return this->a.get_m();
	}
};
int main()
{
	B b1, b2(1);
	B b3(1, 2);
	cout << "b1的n值为:" << b1.get_n() << endl;
	cout << "b1的a的m值为:" << b1.get_am() << endl;
	cout << "b2的n值为:" << b2.get_n() << endl;
	cout << "b2的a的m值为:" << b2.get_am() << endl;
	cout << "b3的n值为:" << b3.get_n() << endl;
	cout << "b3的a的m值为:" << b3.get_am() << endl;
}

6.拷贝构造函数

(1).一般用法

#include<iostream>
using namespace std;
class A
{
	int m;
public:
	A() { m = 0; }//默认构造函数
	A(int i) { m = i; }
	A(const A& a)//拷贝构造函数,若不声明拷贝构造函数,则系统会隐式地给出
	{
		this->m = a.m;
	}
public:
	int get_m()
	{
		return m;
	}
};
int main()
{
	A a1(1);
	A a2(a1);
	cout << a2.get_m() << endl;
}

(2).显示拷贝构造函数

#include<iostream>
using namespace std;
class A
{
	int x, y;
	char* p;
public:
	A(char* str)
	{
		x = 0;
		y = 0;
		p = new char[strlen(str) + 1];
		strcpy(p, str);
	}
	~A() { delete[]p; p = NULL; }
    A(const A& a);
public:
	char * get_p()
	{
		return p;
	}
};
A::A(const A& a)
{
	x = a.x;
	y = a.y;
	p = new char[strlen(a.p) + 1];
	strcpy(p, a.p);
}
int main()
{
	char p[] = "abcd";
	A a1(p);
	A a2(a1); //ERROR:如果使用系统提供的隐式拷贝构造函数,用a1对a2进行初始化,那么会产生以下问题:
	/*
	1.如果对对象a1操作之后修改了这块空间的内容,则对象a2将会受到影响。
	2.当对象a1和a2消亡时,将会分别去调用它们的析构函数,这会使得同一块内存区域被归还两次,从而导致程序异常
	3.当对象a1和a2中有一个消亡,另一个还没消亡时,会出现使用已归还的空间错误。
	*/
	//解决方案:定义一个显示拷贝构造函数
	
	cout << a1.get_p() << endl;
	cout << a2.get_p() << endl;
}

(3).类中包含成员对象时的拷贝构造函数

/*当类定义中有成员对象时,系统提供的隐式拷贝构造函数会调用成员对象的拷贝构造函数,但自定义的拷贝构造函数
* 则会默认调用成员对象的默认构造函数,而不是调用成员对象的拷贝构造函数。
*/
#include<iostream>
using namespace std;
class A
{
	int x, y;
public:
	A() { x = y = 0; }
	void inc() { x++, y++; }
	int get_x() { return x; }
	int get_y() { return y; }
};
class B
{
	int z;
	A a;
public:
	B() { z = 0; }
	B(const B& b) { z = b.z; }
	void inc() { z++; a.inc(); }
	int get_z() { return z; }
	int get_ax() { return a.get_x(); }
	int get_ay() { return a.get_y(); }
};
int main()
{
	B b1;
	b1.inc();
	B b2(b1);
	cout << "b1的z值为:" << b1.get_z() << endl;
	cout << "b1的a的x值为:" << b1.get_ax() << endl;
	cout << "b1的a的y值为:" << b1.get_ay() << endl<<endl;
	cout << "b2的z值为:" << b2.get_z() << endl;
	cout << "b2的a的x值为:" << b2.get_ax() << endl;
	cout << "b2的a的y值为:" << b2.get_ay() << endl;
	//解决方法,显示定义拷贝构造函数
	//B(const B&b):a(b.a){z=b.z;}
}

7.const成员函数

#include<iostream>
using namespace std;
class A
{
	int x;
	char* p;
public:
	void f()const//不改变类中参数的值,函数括号后加“const”
	{
		//x = 1; //ERROR,会报错
		*p = 'A';//不会报错,因为没有改变p的值,需要自己把握
	}
};
class B
{
	int x, y;
public:
	void f()const
	{
		cout << "This is Func f" << endl;
	}
	void g()
	{
		cout << "This is Func g" << endl;
	}
};
int main()
{
	//还可以检验常量对象
	const B b;
	b.f();//OK
	//b.g();  //ERROR
}

8.静态数据成员

#include<iostream>
using namespace std;
class A
{
	int x, y;
	static int shared;
public:
	A() { x = y = 0; }
	void increase_all() { x++; y++; shared++; }
	int sum_all()const { return x + y + shared; }
	int get_z()const { return shared; }
};
int A::shared = 0;
class B
{
	int x, y;
	static int z;
public:
	B() { x = y = 0; }
	static void set_z(int i) { z = i; }//静态成员函数,只能对静态变量进行操作,且没有隐藏的this指针
	static int get_z() { return z; }
};
int B::z;
int main()
{

	A a1,a2;
	cout << "一开始a2中静态变量shared的值为:" << a2.get_z() << endl << endl;
	a1.increase_all();
	cout << "由于所有对象的静态变量shared都只存在一个拷贝,改编a1中shared的值,a2中shared的值也会跟着改编,故自增后shared的值为:" << a2.get_z() << endl;
	
	B b1;
	//访问静态成员函数的两种方式:
	//1.通过对象进行访问
	b1.set_z(10);
	//2.通过类名受限访问
	cout << "b1设置的z值为:" << B::get_z() << endl;
}

9.友元

(1).不使用友元实现矩阵和向量乘法

//友元,可以提高访问效率
//友元不具有传递性
//例:用类来实现矩阵和向量类型并实现矩阵向量相乘操作
#include<iostream>
using namespace std;
class Matrix
{
	int* p_data;
	int row, col;
public:
	Matrix(int r, int c)
	{
		if (r <= 0 || c <= 0)
		{
			cerr << "矩阵尺寸不合法!" << endl;
			exit(-1);
		}
		row = r, col = c;
		p_data = new int[row * col];
	}
	~Matrix()
	{
		delete[]p_data;
	}
	int& element(int i, int j)//访问矩阵元素
	{
		if (i < 0 || i >= row || j < 0 || j >= col)
		{
			cerr << "矩阵下标越界\n";
			exit(-1);
		}
		return*(p_data + i * col + j);
	}
	int element(int i, int j)const//访问矩阵元素(为常量对象提供)
	{
		if (i < 0 || i >= row || j < 0 || j >= col)
		{
			cerr << "矩阵下标越界\n";
			exit(-1);
		}
		return*(p_data + i * col + j);
	}
	int dimension_row()const
	{
		return row;
	}
	int dimension_col()const
	{
		return col;
	}
	void display()const//显示矩阵元素
	{
		int* p = p_data;
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				cout << *p << ' ';
				p++;
			}
			cout << endl;
		}
	}
};
class Vector//向量类
{
	int* p_data;
	int num;
public:
	Vector(int n)
	{
		if (n <= 0)
		{
			cerr << "向量尺寸不合法!\n";
			exit(-1);
		}
		num = n;
		p_data = new int[num];
	}
	~Vector()
	{
		delete[]p_data;
	}
	int& element(int i)
	{
		if (i < 0 || i >= num)
		{
			cerr << "数组下标越界\n";
			exit(-1);
		}
		return p_data[i];
	}
	int element(int i)const
	{
		if (i < 0 || i >= num)
		{
			cerr << "数组下标越界\n";
			exit(-1);
		}
		return p_data[i];
	}
	int dimension()const
	{
		return num;
	}
	void display()const
	{
		int* p = p_data;
		for (int i = 0; i < num; i++, p++)
			cout << *p << ' ';
		cout << endl;
	}
};
void multiply(const Matrix& m, const Vector& v, Vector& r)
{
	if (m.dimension_col() != v.dimension() ||
		m.dimension_row() != r.dimension())
	{
		cerr << "矩阵和向量尺寸不匹配!" << endl;
		exit(-1);
	}
	int row = m.dimension_row();
	int col = m.dimension_col();
	for (int i = 0; i < row; i++)
	{
		r.element(i) = 0;
		for (int j = 0; j < col; j++)
			r.element(i) += m.element(i, j) * v.element(j);
	}
}
int main()
{
	int row, column;
	cout << "请输入矩阵的行数和列数:";
	cin >> row >> column;
	Matrix m(row, column);
	Vector v(column);
	Vector r(row);
	cout << "请输入矩阵元素:\n";
	int i, j;
	for (i = 0; i < row; i++)
		for (j = 0; j < column; j++)
			cin >> m.element(i, j);
	cout << "请输入向量元素:\n";
	for (int i = 0; i < column; i++)
		cin >> v.element(i);
	multiply(m, v, r);
	cout << "矩阵:\n";
	m.display();
	cout << "与向量:\n";
	v.display();
	cout << "的乘积为:\n";
	r.display();
	return 0;
	//上述函数multiply中多次调用成员函数element访问元素,每一次调用都要判断下标是否合法,效率不高
	//可以使用友元函数,在函数中直接取存它们的私有成员,访问效率大大提高
}

(2).使用友元实现(1)中功能

//接上友元
#include<iostream>
using namespace std;
class Vector;//先声明,以后会用到
class Matrix
{
	int* p_data;
	int row, col;
public:
	Matrix(int r, int c)
	{
		if (r <= 0 || c <= 0)
		{
			cerr << "矩阵尺寸不合法!" << endl;
			exit(-1);
		}
		row = r, col = c;
		p_data = new int[row * col];
	}
	~Matrix()
	{
		delete[]p_data;
	}
	int& element(int i, int j)//访问矩阵元素
	{
		if (i < 0 || i >= row || j < 0 || j >= col)
		{
			cerr << "矩阵下标越界\n";
			exit(-1);
		}
		return*(p_data + i * col + j);
	}
	int element(int i, int j)const//访问矩阵元素(为常量对象提供)
	{
		if (i < 0 || i >= row || j < 0 || j >= col)
		{
			cerr << "矩阵下标越界\n";
			exit(-1);
		}
		return*(p_data + i * col + j);
	}
	int dimension_row()const
	{
		return row;
	}
	int dimension_col()const
	{
		return col;
	}
	void display()const//显示矩阵元素
	{
		int* p = p_data;
		for (int i = 0; i < row; i++)
		{
			for (int j = 0; j < col; j++)
			{
				cout << *p << ' ';
				p++;
			}
			cout << endl;
		}
	}
	friend void multiply(const Matrix& m, const Vector& v, Vector& r);
};
class Vector//向量类
{
	int* p_data;
	int num;
public:
	Vector(int n)
	{
		if (n <= 0)
		{
			cerr << "向量尺寸不合法!\n";
			exit(-1);
		}
		num = n;
		p_data = new int[num];
	}
	~Vector()
	{
		delete[]p_data;
	}
	int& element(int i)
	{
		if (i < 0 || i >= num)
		{
			cerr << "数组下标越界\n";
			exit(-1);
		}
		return p_data[i];
	}
	int element(int i)const
	{
		if (i < 0 || i >= num)
		{
			cerr << "数组下标越界\n";
			exit(-1);
		}
		return p_data[i];
	}
	int dimension()const
	{
		return num;
	}
	void display()const
	{
		int* p = p_data;
		for (int i = 0; i < num; i++, p++)
			cout << *p << ' ';
		cout << endl;
	}
	friend void multiply(const Matrix& m, const Vector& v, Vector& r);
};
void multiply(const Matrix& m, const Vector& v, Vector& r)
{
	if (m.col!= v.num ||
		m.row != r.num)
	{
		cerr << "矩阵和向量尺寸不匹配!" << endl;
		exit(-1);
	}
	int* p_m = m.p_data, * p_r = r.p_data, * p_v;
	for (int i = 0; i < m.row; i++)
	{
		*p_r = 0;
		p_v = v.p_data;
		for (int j = 0; j < m.col; j++)
		{
			*p_r += (*p_m) * (*p_v);
			p_m++;
			p_v++;
		}
		p_r++;
	}
}
int main()
{
	int row, column;
	cout << "请输入矩阵的行数和列数:";
	cin >> row >> column;
	Matrix m(row, column);
	Vector v(column);
	Vector r(row);
	cout << "请输入矩阵元素:\n";
	int i, j;
	for (i = 0; i < row; i++)
		for (j = 0; j < column; j++)
			cin >> m.element(i, j);
	cout << "请输入向量元素:\n";
	for (int i = 0; i < column; i++)
		cin >> v.element(i);
	multiply(m, v, r);
	cout << "矩阵:\n";
	m.display();
	cout << "与向量:\n";
	v.display();
	cout << "的乘积为:\n";
	r.display();
	return 0;
	//上述函数multiply中多次调用成员函数element访问元素,每一次调用都要判断下标是否合法,效率不高
	//可以使用友元函数,在函数中直接取存它们的私有成员,访问效率大大提高
}

10.构造转移函数

//对象拷贝构造的优化——构造转移函数
/*当用一个即将消亡的对象去初始化另一个同类对象时,有时目前的拷贝构造函数实现效率并不高,例如
* ,对于下面的程序:
*/
#include<iostream>
using namespace std;
class A
{
	char* p;
public:
	A(char* str) { p = new char[strlen(str) + 1]; strcpy(p, str); }
	A(const A& x)
	{
		p = new char[strlen(x.p) + 1]; strcpy(p, x.p);
	}
	~A()
	{
		delete[]p;
		p = NULL;
	}
	//转移构造函数
	A(A&& x)
	{
		p = x.p;//把参数对象x的p所指向的空间作为新对象的p所指的空间(资源转移)
		x.p = NULL;//使得参数对象x的p不再拥有原来所指向的空间
	}
	friend int main();
};
A f()
{
	char p[] = "1234";
	A t(p);
	//......一系列操作
	return t;//如果不加转移构造函数,这时候需要:创建返回值对象,用即将消亡的对象t对其进行初始化(调用拷贝构造函数),对象t消亡
}
int main()
{
	A a = f();
	cout << a.p << endl;
	//要避免为返回值对象申请新空间、内容复制以及归还对象t申请的空间所带来的开销,可以使用转移构造函数

}

11.操作符重载

(1).一般双目操作符重载(+,-,*,/)和一般单目操作符重载

//操作符重载:
//c++中没有对类等专门定义操作符(+,-,*,/),可以通过操作符重载来实现
//形式:<函数类型> <operator> <某个操作符> (参数)

//也可以作为全局函数定义
//操作符重载的基本原则
//1.遵循已有操作符的语法
//2.遵循已有操作符的语义
//3.可重载的操作符:除下面五个操作符外其余皆可重载
//“.”(成员选择符) “.*”(间接成员选择符) “::”(域解析符)“?:”(条件操作符)“sizeof”(数据占内存大小)

//双目操作符重载:
//形式(作为成员函数):<返回值类型> operator <运算符> (<类型>)
//使用格式:<类名> a; <类名> b; a#b; (#为定义的运算符)
//或 a.operator#(b)

//单目操作符重载:
//形式:<返回值类型> operator <运算符> (<类型>)

//实现复数加减乘除,==,!=和-
class Complex
{
	double real, imag;
public:
	Complex(double r = 0.0, double i = 0.0) { real = r, imag = i; }
	void display()const
	{
		if (real != 0)
		{
			cout << real;
			if (imag > 0)
			{
				cout << '+' << imag << 'i';
				return;
			}
			else if (imag == 0)
				return;
			else if (imag < 0)
			{
				cout << imag << 'i';
				return;
			}
		}
		else
		{
			if (imag > 0)
			{
				cout << imag << 'i';
				return;
			}
			else if (imag == 0)
			{
				cout << 0;
				return;
			}
			else if (imag < 0)
			{
				cout << imag << 'i';
				return;
			}
		}
	}
public:
	//双目操作符重载
	Complex operator + (const Complex& x)const
	{
		Complex temp;
		temp.real = real + x.real;
		temp.imag = imag + x.imag;
		return temp;
	}
	Complex operator -(const Complex& x)const
	{
		Complex temp;
		temp.real = real - x.real;
		temp.imag = imag - x.imag;
		return temp;
	}
	Complex operator *(const Complex& x)const
	{
		Complex temp;
		temp.real = real * x.real - imag * x.imag;
		temp.imag = imag * x.real + real * x.imag;
		return temp;
	}
	Complex operator /(const Complex& x)const
	{
		Complex temp;
		Complex conj(x.real, -x.imag);
		temp = *this * conj;
		int mod_x = x.real * x.real + x.imag * x.imag;
		temp.real = temp.real / mod_x;
		temp.imag = temp.imag / mod_x;
		return temp;
	}
	bool operator ==(const Complex& x)const
	{
		return (real == x.real) && (imag == x.imag);
	}
	bool operator !=(const Complex& x)const
	{
		return !(*this == x);
	}
	//单目操作符重载
	Complex operator -() const
	{
		Complex temp;
		temp.real = -real;
		temp.imag = -imag;
		return temp;
	}
};
int main()
{
	Complex c1(1, 3);
	Complex c2(1, -3);
	Complex c3 = c1 + c2;
	Complex c4 = c1 - c2;
	Complex c5 = c1 * c2;
	Complex c6 = c1 / c2;
	cout << "复数";
	c1.display();
	cout << "与复数";
	c2.display();
	cout << "的和为:";
	c3.display();
	cout << endl;
	cout << "差为:";
	c4.display();
	cout << endl;
	cout << "乘积为:";
	c5.display();
	cout << endl;
	cout << "商为:";
	c6.display();
	cout << endl;
	if (c1 == c2)
		cout << "c1和c2相等" << endl;
	else if (c1 != c2)
		cout << "c1和c2不相等" << endl;
}

(2). 自增和自减的重载

//自增和自减的实现
#include<iostream>
using namespace std;
class Counter
{
	int value;
public:
	Counter(){ value = 0; }
	Counter(int i) { value = i; }
	Counter& operator ++() //前置++,返回地址,是因为c++规定前置++返回地址,不然无法执行++a+=1这种操作
	{
		value++;
		return *this;//先加后用
	}
	const Counter operator ++(int)//int参数只起区分作用
	{
		Counter temp = *this;//先用后加
		++(*this);
		return temp;
	}
	friend int main();
	friend Counter operator !(Counter c);
};
//作为全局函数重载单目操作符
Counter operator ! (Counter c)
{
	Counter temp(!(c.value));
	return temp;
}
int main()
{
	Counter c1, c2, c3,c4;
	c2 = c1++;
	c3 = ++c1;
	c4 = !c1;
	cout << c1.value;
	cout << "c1:" << c1.value << endl;
	cout << "c2:" << c2.value << endl;
	cout << "c3:" << c3.value << endl;
	cout << "c4:" << c4.value << endl;
}

(3).特殊操作符的重载

1)."="赋值操作重载
//C++一些特殊操作符的重载
//1.“ = ”的重载(成员包含指针时,隐式的拷贝构造函数往往不能满足需求,会产生“孤儿”空间)
#include<iostream>
using namespace std;
class A
{
	int x, y;
	char* p;
public:
	A() { x = y = 0; p = NULL; }
	A(const char* str)
	{
		p = new char[strlen(str) + 1];
		strcpy(p, str);
		x = y = 0;
	}
	~A()
	{
		cout << "析构函数被调用。" << endl;
		delete[]p;
		p = NULL;
	}
	A(const A& x)
	{
		p = new char[strlen(x.p) + 1]; strcpy(p, x.p);

	}
     A& operator =(const A& a)
	{
		 cout << "此时调用赋值操作符函数。" << endl;
		 if (&a == this)return *this;//防止自身赋值
		 delete[]p;
		 p = new char[strlen(a.p) + 1];
		 strcpy(p, a.p);
		 x = a.x, y = a.y;
		 return *this;
	}
	 A& operator =(A&& x)//注意!!!实现该函数必须得实现拷贝构造函数!
	 {
		 cout << "此时调用转移赋值操作符函数。" << endl;
		 delete[]p;
		 p = x.p;
		 x.p = NULL;
		 return *this;
	 }
	 friend int main();
};

A f()
{
	A temp("ijkl");
	return temp;
}
int main()
{
	cout << "注意!实现转移赋值函数时必须实现拷贝构造函数!" << endl;
	A a1("abcd"), a2("efgh");//初始化
	a1 = a2;//调用 = 的重载函数
	a1 = f();//调用转移赋值函数
}
2)数组元素访问符的重载
#include<iostream>
using namespace std;
class String
{
	char* p;
public:
	String() { p = NULL; }
	String(const char str[]) { p = new char[strlen(str) + 1]; strcpy(p, str); }
	~String() { delete[]p; p = NULL; }
public:
	char& operator [](int i)
	{
		if (i < 0 || i >= strlen(p))
		{
			cerr << "数组下标越界!" << endl;
			exit(-1);
		}
		return p[i];
	}
};
int main()
{
	String s("abcd");
	for (int i = 0; i < 4; i++)
		cout << "s[" << i << "]: " << s[i] << endl;
}
3)"new"的重载
//new有两个功能:为动态对象分配空间和调用对象类的构造函数
//重载的是它分配空间的功能,不影响对构造函数和析构函数的调用
//在c++中,new只能作为类的静态成员来重载(static说明可以不写)

//格式为:void *operator new(size_t size,...);
//返回类型必须为void *,第一个参数size是需要分配的内存空间大小,其类型为size_t(unsigned int),其他参数可有可无
#include<cstring>
#include<cstdlib>
class A
{
	int x, y;
public:
	void* operator new(size_t size)
	{
		void* p = malloc(size);//申请堆空间
		memset(p, 0, size);//memset为c++标准库函数,把申请到堆的空间初始化为全“0”;
		return p;
	}
};
class B
{
	int x, y;
public:
	B() { x = y = 0; }
	B(int i) { x = y = i; }
	void* operator new(size_t size,void *p)//也可以有多个参数
	{
		return p;
	}
	friend int main();
};
int main()
{
	A* p = new A;
    char buf[sizeof(B)];
	B* p1 = new (buf)B(0);//含有其他参数时,创建方式为:A*p=new(...)A;
}

上面操作符new重载函数的行为与系统提供的new功能差不多,区别在于它对申请来的空间进行了初始化,其好处是为一个没有任何构造函数的类的对象提供初始化。

对于上面动态对象的创建,其内存空间不是在程序的堆区分配,而是由创建者提供的。对于这样的动态 对象,如果要使其消亡,则不应该用delete操作,而是通过直接调用对象类的析构函数来实现:

p->~A();

如果使用delete操作来撤销上面的动态对象,将会导致程序异常终止,这是因为系统提供的delete操作将会把对象的空间归还到程序的堆区中,而该对象的空间不是在程序堆区中分配的。

4)“delete”的重载

一般来说,如果对某个类重载了操作符new,则相应地也要重载操作符delete。操作符delete也必须作为静态的成员函数来重载,其格式为:void operator delete(void *p,size_t size);

<*>用重载操作符new与delete来管理某类对象的堆空间

内存管理,狗都不做

#include<cstring>
#include<cstdlib>
const int NUM = 12;
class A
{
public:
	static void* operator new(size_t size);
	static void operator delete(void* p);
private:
	static A* p_free;
	A* next;
};
A* A::p_free = NULL;
void* A::operator new(size_t size)
{
	A* p;
	if (p_free == NULL)
	{
		p_free = (A*)malloc(size * NUM);
		for (p = p_free; p != p_free + NUM - 1; p++)
			p->next = p + 1;
		p->next = NULL;
	}
	p = p_free;
	p_free = p_free->next;
	memset(p, 0, size);//把对象空间初始化为全“0”。如果类中有构造函数,这个操作可以不要
	return p;
}
void A::operator delete(void* p)
{
	((A*)p)->next = p_free;
	p_free = (A*)p;
}
5)函数调用操作符"()"的重载
#include<iostream>
using namespace std;
class A
{
	int value;
public:
	A() { value = 0; }
	A(int i) { value = i; }
	int operator ()(int x)
	{
		cout << "此时调用函数调用重载。" << endl;
		return x + value;
	}
};
int main()
{
	A a(3);//初始化a为3
	cout << a(10) << endl;//可以看作调用函数“a”,应该输出13
}

函数调用操作符重载主要应用于只有一个操作的对象——函数对象,该对象除了具有一般的函数行为外,它还可以拥有状态,可以实现含有static存储类的局部变量的全局函数功能。例如,下面的函数对象random实现了随机函数的功能:

#include<iostream>
using namespace std;
class Random
{
	unsigned int seed;
public:
	Random(unsigned int i)
	{
		seed = i;
	}
	unsigned int operator()()
	{
		seed = (25173 * seed + 13849) % 65536;
		return seed;
	}
};
int main()
{
	Random random(1);//改变初始化的值将会得到不同的随机数
	cout << random();
}
6)间接类成员访问操作符”->“重载

通过对其进行重载可以实现一种“智能指针”,用该指针另访问一个对象的访问成员时,能在访问前做一些额外的事情

//实现在程序执行的某个时刻能够获得一个对象的访问次数
#include<iostream>
using namespace std;
class A
{
	int x, y;
public:
	void f() { cout << "这是函数f。" << endl; }
	void g() { cout << "这是函数g。" << endl; }
};
class B//智能指针类
{
	A* p_a;
	int count;
public:
	B(A* p)
	{
		p_a = p;
		count = 0;
	}
	~B()
	{
		p_a = NULL;
	}
	A* operator ->()
	{
		count++;
		return p_a;
	}
	int num_of_A_access()const
	{
		return count;
	}
};
void func(B& p)
{
	p->f();
	p->g();
}
int main()
{
	A a;
	B b(&a);
	func(b);
	cout << "借由智能指针得出访问对象a的次数为:" << b.num_of_A_access() << endl;
}
7)类型转换操作符重载
<1>.带一个参数的构造函数用作类型转换

带一个参数的构造函数可以用作从一个基本数据类型或其他类到一个类的转换。

#include<iostream>
using namespace std;
class Complex
{
	double real, imag;
public:
	Complex() { real = imag = 0; }
	Complex(double r) { real = r, imag = 0; }
	Complex(double r, double i) { real = r, imag = i; }
	friend Complex operator +(const Complex& x, const Complex& y);
};
Complex operator +(const Complex& x, const Complex& y)
{
	Complex temp;
	temp.real = x.real + y.real;
	temp.imag = x.imag + y.imag;
	return temp;
}
int main()
{
	Complex c1(1, 2), c2, c3;
	c2 = c1 + 1.7;//1.7隐式转换成一个复数对象Complex(1.7)
	c3 = 2.5 + c2;//2.5隐式转换成一个复数对象Complex(2.5)
}
<2>.自定义类型转换
#include<iostream>
using namespace std;
class A
{
	int x, y;
public:
	operator int() { return x + y; }
};
int main()
{
    A a;
	int i = 1;
	int z = i + a;//将调用类型转换操作符int的重载函数
}
<3>.上述两点歧义问题的解决

当一个类中同时定义了具有一个参数(t类型)的构造函数和t类型转换操作符重载函数时,将会产生歧义问题。例如:

class A
{
	int x, y;
public:
    A(){x=0;y=0;}
    A(int i){x=i;y=0;}
	operator int() { return x + y; }
	friend A operator +(const A& a1, const A& a2);
};
A operator +(const A& a1, const A& a2)
{
	A temp;
	temp.x = a1.x + a2.x;
	temp.y = a1.y + a2.y;
}
int main()
{
    A a;
    int i=1,z;
    z=a+i;//是a转换成int还是i转换成A?
}

可以用显示类型转换解决:

z=int(a)+i;

z=a+A(i);

也可以通过给A类的构造函数A(int i)前加一个修饰符explicit来解决:

explicit A(int i){x=i,y=0;}

explicit的含义是:禁止把A(int i)当作隐式类型转换符使用。这样,上面的“a+i;”就只有一个含义:把a转成int。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值