c++学习笔记(初学)
2016-08-08 12:40
204 查看
第 11 章 使用类
一、运算符重载旨在让我们能够用同名的函数来完成相同的基本操作。
例如,在一个计算时间的类中,我们定义了一个计算时间和的函数:
Time Time::Sum(const Time & t) const //将参数声明为引用的目的是提高效率 { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes / 60; sum.minutes %= 60; return sum; //返回值不能是引用 }调用该函数的方法是:
Time total;
total = coding.Sum(fixing); //其中coding和fixing是Time的两个已赋值对象
这时,我们可以将Time类转换为重载的加法运算符:
Time Time::operator+(const Time & t) const { Time sum; sum.minutes = minutes + t.minutes; sum.hours = hours + t.hours + sum.minutes / 60; sum.minutes %= 60; return sum; }这时,我们就可以使用运算符表示法:total = coding + fixing;
或者也可以total = coding.operator+(fixing);
注意,运算符左侧的对象是调用对象,右边的对象是作为参数被传递的对象。
二、友元
由上一小节可知,重载运算符后,运算符左侧的对象是调用对象,右边的对象是作为参数被传递的对象。但如果有以下语句:A = 2.75 * B;将会编译错误。而我们知道,非成员函数不是由对象调用的,它使用的所有值都是显示参数。故我们通过让非成员函数成为类的友元,可以赋予该函数与类的成员函数相同的访问权限。
函数实例如下:
friend Time operator*(double m, const Time & t);
注意:
① 不能用成员运算符来调用;
② 不是成员函数但与成员函数的访问权限相同;
③ 函数定义不要使用解析运算符::;
4000
④ 不要在定义中使用关键字friend。
重载<<运算符
1、要使Time类知道使用cout,必须使用友元函数:
void operator<<(ostream & os, const Time & t) { os << t.hours << " hours, " << t.minutes << " minutes"; }这样可以使用这样的语句:cout << trip;
2、然而,倘若要使cout << "Trip time: " << trip << " (Tuesday)\n"情况允许,则只要修改operator<<()函数,让它返回ostream对象的引用即可:
ostream & operator<<(ostream & os, const Time & t) { os << t.hours << " hours, " << t.minutes << " minutes"; return os; }
三、类的实例(矢量类)
使用了类的重载和友元的类设计
#ifndef VECTOR_H_ #define VECTOR_H_ #include<iostream> namespace VECTOR //将类声明放在VECTOR名称空间中 { class Vector { public: enum Mode {RECT, POL}; //用于标识两种表示法 直角坐标和极坐标 private: double x; double y; double mag; double ang; Mode mode; void set_mag(); void set_ang(); void set_x(); void set_y(); public: Vector(); Vector(double n1,double n2,Mode form = RECT); void reset(double n1,double n2,Mode form = RECT); ~Vector(); //声明不会对其显示访问的对象进行修改的函数用const限定符 double xval() const {return x;} double yval() const {return y;} double magval() const {return mag;} double angval() const {return ang;} //将自动成为内联函数 void polar_mode(); void rect_mode(); Vector operator+(const Vector & b) const; Vector operator-(const Vector & b) const; Vector operator-() const; Vector operator*(double n) const; friend Vector operator*(double n,const Vector & a); friend std::ostream & operator<<(std::ostream & os,const Vector & v); } } #endif实现:
#include<cmath> #include "vect.h" using std::sqrt; using std::sin; using std::cos; using std::atan; using std::atan2; using std::cout; namespace VECTOR { const double Rad_to_deg = 45.0 / atan(1.0); //约为57.2957795 void Vector::set_mag() { mag = sqrt(x * x + y * y); } void Vector::set_ang() { if(x == 0.0 && y == 0.0) ang = atan2(y,x); } //已知极坐标求直角坐标 void Vector::set_x() { x = mag * cos(ang); } void Vector::set_y() { y = mag * sin(ang); } Vector::Vector() { x = y = mag = 0.0; mode = RECT; } Vector(double n1,double n2,Mode form) { mode = form; if(form == RECT) { x = n1; y = n2; set_mag(); set_ang(); } else if (form = POL) { mag = n1; ang = n2 / Rad_to_deg; set_x(); set_y(); } else { cout << "Incorrect 3rd argument to Vector() -- "; cout << "vector set to 0\n"; x = y = mag = ang = 0.0; mode = RECT; } } void reset(double n1,double n2,Mode form) { mode = form; if(form = RECT) { x = n1; y = n2; set_mag(); set_ang(); } else if(form = POL) { mag = n1; ang = n2 / Rad_to_deg; set_x(); set_y(); } else { cout << "Incorrect 3rd argument to Vector() -- "; cout << "vector set to 0\n"; x = y = mag = ang = 0.0; mode = RECT; } } Vector::~Vector(){} void Vector::polar_mode() { mode = POL; } void Vector::rect_mode() { mode = RECT; } Vector Vector::operator+(const Vector & b) const { return Vector(x + b.x, y + b.y); } //将新的x和y分量传递给构造函数,而后者将使用这些值来创建无名的新对象,并返回该对象的副本 Vector Vector::operator-(const Vector & b) const { return Vector(x - b.x, y - b.y); } Vector Vector::operator-() const //返回与原来矢量相反的矢量 { return Vector(-x,-y); } Vector Vector::operator*(double n) const { return Vector(n * x,n * y); } Vector operator*(double n,const Vector & a) { return a * n; } std::ostream & operator<<(std::ostream & os,const Vector & v) { if(v.mode == Vector::RECT) //因为友元函数不在类作用域内,因此必须使用Vector::RECT,但这个友元函数在名称空间VECTOR中,因此无需使用全限定名VECTOR::Vector::RECT os << "(x,y) = (" << v.x << "," << v.y << ")"); else if(v.mode == Vector::POL) { os << "(m,a) = (" << v.mag << "," << v.ang * Rad_to_deg << ")"; } else os << "Vector object mode is invalid"; return os; } }
ps:随机数的生成
stdlib头文件下的srand()和rand()函数
我们知道,rand()函数可以产生随机数,但这是一个伪随机数,每次执行时都是相同的。若要不同,则需要用srand()函数来设置rand()产生随机数时的随机种子,当用户未设定随机种子时,系统默认的随机种子为1。而我们知道,我们每一次运行程序的时间是不同的,故可以使用time(0)的返回值来设置种子,即srand(time(0))。其中头文件ctime包含了time()的原型。
产生一定范围随机数的通用表达式
a + rand() % n,其中a为起始值,n为整数的范围。
相关文章推荐
- c++学习笔记(初学)
- c++学习笔记2——指向字符串的指针数组?
- C\C++ 程序员从零开始学习Android - 个人学习笔记(三) - java基础 - 环境和工具
- C++学习笔记---类的朋友
- C++学习笔记--函数参数扩展和占位参数
- “Effective C++ Third Edition”学习笔记(四)
- C++基础知识学习笔记(一)
- C++学习笔记之"类和对象I"
- C/C++学习笔记
- Effective C++ 学习笔记(一)
- C++ 学习笔记(一些新特性总结3)
- 2012/1/27 《C++ Primer Plus》第十二章:类和动态内存分配 学习笔记
- C++学习笔记汇总
- 一个月学习C++笔记(三)
- [Linux]C++学习笔记(七)
- [置顶]C++学习笔记之模板篇
- C++学习笔记(10)-信号处理&多线程
- C++学习笔记---STL简介
- 学习笔记31-C/C++字符串输入
- 学习笔记之深入浅出MFC 第8章 C++重要性质---构造函数与析构函数