第十二天(使用类)

本文详细介绍了C++中的操作符重载概念及其应用场景,包括如何重载加法、乘法等操作符,以及如何定义友元函数来增强类的功能。此外,还探讨了如何重载输入输出流操作符<<和>>,并提供了一个复数类的例子。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

      这一章看似很长,其实有很大一部分内容没记得必要:自定义的的Vector类,用来加深重载操作符的印象;类的转换,不是java中的将子类转换成父类,所得的对象应调用父类的方法还是子类的方法那么复杂,而是将基本数据类型与类对象之间的转换,这种转换只能应用于拥有一个参数的构造函数的类,这样的转换应用狭窄,且有一种并不复杂的方法替代。


2011-11-05(Working with Classes)
1、操作符重载(Operator Overloading)。
形式如下:
                     operator op(argumentList);
例:

#include <iostream>

class A
{
private:
    int AMember;
public:
    A(int AM = 5);
    A sum(A&);
    A operator +(A&);
    void show(){std::cout << AMember << " ";}
};

A::A(int AM ){AMember = AM;}

A A::sum(A& guest)
{
    A a;
    a.AMember = this->AMember + guest.AMember;
    return a;
}

A A::operator +(A& guest)
{
    A a;
    a.AMember = this->AMember + guest.AMember;
    return a;
}

int main()
{
    A a[3] = {A(10), A(20), A(30)};
    A result = A();

    result = a[0].sum(a[1]);result.show();
    result = a[1] + a[2];result.show();
    result = a[0].operator+(a[2]);
    result = a[0] + a[1] + a[2];result.show();
}
输出: 30 50 40 60
①可看出,重载操作符和sum的函数体一样,内部的实现还是一样的,不同的是调用起来“+”比“sum”更直观、更突出本质;
②Ob1 op Ob2等效于Ob1.opOverloadingFunc(Ob2),所以左右操作数不能随便交换。根据这个可解释35行;
③重载操作符的参数至多有一个,因为重载的操作符是一元或是二元(不能重载?:操作符)。
2、重载操作符的限制。
①重载后操作符至少有一个操作数是用户自定义类型。否则会产生歧义;
②不能违反语法规则(如不能将二元操作符重载成一元),不能修改优先级(重载时优先级怎么修改?);
③不能自定义操作符,如不能
operator @(),因为C++没有@操作符;
④不能重载下列操作符:
sizeof, .(成员操作符), .*(成员指针操作符), ::, ?:, typeid, const_cast, dynamic_cast, reinterpret_cast, static_cast(后面几个不懂,不解释);
⑤下列操作符只能通过成员函数重载:
=, (), [], ->
3、友元(Friend)。下面的操作符重载:
A A::operator *(int mul)
{
    A a;
    a.a.AMember = this->AMember * mul;
    return a;
}
使用的时候,只能result = a * 5,而不能result = 5 * a。但是,根据我对数学的了解,这二者必然是一样的。实际上,如果参数是两个以上:
                                                   A operator *(int mul, A& a);
则可以将非A对象置于左边。根据1③,这必须不是类的成员函数。然而,要想实现这个函数的功能,必须要访问类的私有变量。矛盾情况下,诞生了友元函数(其实还有友元类、友元成员函数,不过要到后面才提)。这是一种能访问某个类的私有变量的函数。函数的原型在类中加上关键字
friend声明(原因是由类决定哪个函数是友元),其次,友元函数不是类的成员函数,所以定义之时不需加上作用域解析符:“::”。举例如下:
class A
{
    //... ...
    friend A operator *(int,A&);
    //... ...
}
//... ...
A operator *(int mul,A& guest)
{
    A a;
    a.AMember = guest.AMember * mul;
    return a;
}
如此即可使用5 * a来使用重载操作符。但是这样的友元函数的参数列表各参数的顺序是一一对应的,即(int ad,A& guest)对应的是5 * a,而(A& guest, int ad)对应的是a * 5,所以想要实现交换律,必须要定义两个友元函数(或者是一个友元函数,一个类的成员函数)。
**聪明的人可能已经想到了解决那个矛盾的方法: 
A operator *(int mul, A& guest)
{
     return guest * mul;
}
这虽然可以不要友元函数,但这一小点的主题是如何定义和使用友元函数,提之何用?
4、重载<<操作符。
重载<<操作符可替代上述类中show()成员函数,采用:

                         cout << aObject
的形式即可打印A类的对象的相关信息。下面来讨论实现这个功能的相关问题:
①如果重载操作符函数是类的成员函数,则在使用这重载操作符的时只能采用如下形式:
                         aObject << cout
如此形式稍显不妥,所以可使用友元函数;
②从前面知道,
cout是ostream的一个对象,所以重载函数的第一个参数即是ostream对象的引用,第二个参数即是A的对象的引用:
                         void operator <<(ostream&, A&);
如此,在使用cout << aObject的时候即是调用了:
                         operator <<(cout, aObject);
③上述的函数原型,有一个问题:
                         cout << aObject1 << aObject2; 
是不能工作的,因为cout << aObject1返回的是
void,不能使用<<打印后面的aObject2。因此,重载的函数返回类型也必须是ostream的对象:
                         ostream& operator <<(ostream&, A&);
综上,可实现如下:
class A
{
    //… …
    friend std::ostream& operator <<(std::ostream&, A&);
};

std::ostream& operator <<(std::ostream& os, A& a)
{
    os << "AMember = " << a.AMember << std::endl;
    return os;
}
5、产生伪随机数。
C/C++库中提供一个rand()
函数来生成0到RAND_MAX(=SHRT_MAX)的伪随机数。如果想要范围缩小,通常的做法是配合取模操作符来产生:
                      rand() % 100//create 0~100 random number
单单使用rand()函数,因为其中的算法是一样的,所以同一平台每次运行的产生随机数都是一样的。所以rand()需要一个产生随机数的种子(Seed),根据种子的不同可产生不同的随机序列。设置随机种子可使用
                      srand(unsigned seed);
然而,如果程序都固定设置一个种子,如:
unsigned int seed = 15;
srand(seed);
std::cout << rand();
每次运行的结果依然一样。是什么在每次运行程序的时候都不一样?是时间。所以通常的做法是用当前时间作为种子,使伪随机更像随机:
                     
srand((unsigned)time(0));
time(0)返回的即是当前时间。
**需要头文件
cstdlib和ctime来支持srand, rand和time


再来个课后习题:

定义复数类,重载+, -, *, ~, <<, >>操作符

//fileName:complex0.h--the declaration of class
#ifndef COMPLEXX_H_
#define	COMPLEXX_H_

#include <iostream>

using std::istream;
using std::ostream;

class complex
{
private:
	double realPart;
	double imagPart;
public:
	complex(double rP = 0, double iP = 0);
	~complex();
	complex operator +(const complex&)const;
	complex operator -(const complex&)const;
	complex operator *(const complex&)const;
	complex operator ~();

	friend complex operator *(double,const complex&);
	friend ostream& operator <<(ostream&,const complex&);
	friend istream& operator >>(istream&,complex&);
};
#endif

//fileName:complex0.cpp--the implementation of class
#include "complex0.h"

using std::cout;
using std::cin;

complex::complex(double rP, double iP)
{
	realPart = rP;
	imagPart = iP;
}

complex::~complex(){}

complex complex::operator +(const complex& im)const
{
	return complex(realPart + im.realPart, imagPart + im.imagPart);
}

complex complex::operator -(const complex& im)const
{
	return complex(realPart - im.realPart, imagPart - im.imagPart);
}

complex complex::operator *(const  complex& im)const
{
	return complex(realPart * im.realPart, imagPart * im.imagPart);
}

complex complex::operator~()
{
	return complex(-realPart, -imagPart);
}
//define friend function
complex operator *(double fact,const complex& im)
{
	return complex(fact * im.realPart, fact * im.imagPart);
}

ostream& operator <<(ostream& os,const complex& im)
{
	os << "(" << im.realPart << ", " << im.imagPart << "i)";
	return os;
}

istream& operator >>(istream& is, complex& im)
{
	cout << "real: ";
	if(is >> im.realPart)
	{
		cout << "imaginary: ";
		is >> im.imagPart;
	}
	return is;
}
//fileName:Test.cpp--the test of class
#include <iostream>
using namespace std;
#include "complex0.h"  // to avoid confusion with complex.h

int main()
{
	complex a(3.0, 4.0);   // initialize to (3,4i)
	complex c;
	cout << "Enter a complex number (q to quit):\n";
	while (cin >> c)
	{
		cout << "c is " << c << "\n";
		cout << "complex conjugate is " << ~c << "\n";
		cout << "a is " << a << "\n";
		cout << "a + c is " << a + c << "\n";
		cout << "a - c is " << a - c << "\n";
		cout << "a * c is " << a * c << "\n";
		cout << "2 * c is " << 2 * c << "\n";
		cout << "Enter a complex number (q to quit):\n";
	}
	cout << "Done!\n";
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值