c++入门之 再话类
对于类,其结构并不难,但要理解其设计思想也并不容易,在此,我们可以通过下面的代码进一步理解和使用类:
# ifndef VECTOR_H_
# define VECTOR_H_
# include "iostream" namespace 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();//析构函数
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
该类定义中:除了备注的一些以外,总结这么几点:
1 定义了一个类的时候,限定了该类的名称空间通常是一件好事,以免自己的变量和别人的发生了冲突
2 公有还是私有并无界限之分,完全取决于程序的功能。
3 我们通常会发现:当定义一个类成员函数时,通常需要:构造函数,析构函数,甚至友元函数
4 私有成员(无论是变量还是函数)只能被类内部的成员进行访问,而共有成员 可以被其他类甚至其他任何东西访问。究其本质:公有部分 是提供的接口
下面给出该定义:
# include"cmath" //从下文的调用方法来看,这里应该是函数库,而不是类库
# include "vector.h"
using std::sqrt; //注意 std 包含了很多
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);
void Vector::set_ang()
{
mag = sqrt(x*x + y*y); //求极长
} void Vector::set_ang()
{
if (x == 0.0 && y == 0.0)
ang = 0.0;
else
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 = ang = 0.0;
mode = RECT;
} Vector::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;
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 Vector::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;
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);
} 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(n*x,x*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)
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";
}
}
1. 我们注意107行和112行的代码:本质上,进行了加法和减法之后,得到的是一个新的类对象,但由于这个类对象不止一种表示形式(直角坐标和极坐标),这里巧妙的利用了 返回构造函数的执行。这告诉我们:构造函数并不仅仅用于初始化,构造函数的本意:构造新的对象,一定要认识这一本质特征和思想。
2 我们注意124行的代码:return a*n; 本质上,对象乘以一个数无法实现,但这里,其实,并没有返回,而是回去重新调用了上面的*。
3 注意:129行和131行:if (v.mode == Vector::RECT)。为何要加Vector::RECT而不是RECT,这是因为:
友元函数虽然在public中,但友元函数并不在类作用域中!!! 这对于所有友元函数都成立!!!
c++入门之 再话类的更多相关文章
- c++入门之再话内存和引用
此处没有代码,仅仅讨论一些这样的问题:我们为何使用引用?在哪里使用引用? 首先从函数的角度思考?:函数进行一般参数传递的时候,是怎么样传递的?普通类型的参数传递,是将传递的实参复制一份,到另一个内存空 ...
- c++入门之再话命名空间的意义
c++中使用了命名空间这一概念,通过下面这个代码,我们将深刻认识到命名空间的重要作用和意义: # include"iostream" using namespace std; na ...
- JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式
相关链接: JS面向对象(1) -- 简介,入门,系统常用类,自定义类,constructor,typeof,instanceof,对象在内存中的表现形式 JS面向对象(2) -- this的使用,对 ...
- Python编程从入门到实践笔记——类
Python编程从入门到实践笔记——类 #coding=gbk #Python编程从入门到实践笔记——类 #9.1创建和使用类 #1.创建Dog类 class Dog():#类名首字母大写 " ...
- python入门学习:8.类
python入门学习:8.类 关键点:类 8.1 创建和使用类8.2 使用类和实例8.3 继承8.4 导入类 8.1 创建和使用类 面向对象编程是最有效的软件编写方法之一.在面向对象编程中,你编写 ...
- Node.js开发入门—HelloWorld再分析
在Node.js开发入门(1)我们用http模块实现了一个简单的HelloWorld站点,这次我们再来细致分析下代码.了解很多其它的细节. 先看看http版本号的HelloWorld代码: 代码就是这 ...
- Python 3 快速入门 3 —— 模块与类
本文假设你已经有一门面向对象编程语言基础,如Java等,且希望快速了解并使用Python语言.本文对重点语法和数据结构以及用法进行详细说明,同时对一些难以理解的点进行了图解,以便大家快速入门.一些较偏 ...
- 【PHP面向对象(OOP)编程入门教程】11.类的继承
继承作为面向对象的三个重要特性的一个方面,在面向对象的领域有着及其重要的作用,好像没听说哪个面向对象的语言不支持继承. 继承是PHP5面象对象程序设计的重要特性之一,它是指建立一个新的派生类,从一个或 ...
- Java+7入门经典 - 6 扩展类与继承 Part 1/2
第6章 扩展类与继承 面向对象编程的一个重要特性: 允许基于已定义的类创建新的类; 6.1 使用已有的类 派生 derivation, 派生类 derived class, 直接子类 direct s ...
随机推荐
- c# 建立到数据源的连接 以及获取项目配置文件的属性
两种连接数据库的写法: <connectionStrings> <add name="HRModelsContainer" connectionString=&q ...
- visual studio 启动无法打开IIS express
删除 解决方案下的vs文件夹之后重新生成
- Python 标示符和关键字
标示符 开发人员在程序中自定义的一些符号和名称.标示符是自己定义的,如变量名 .函数名等 标示符的规则 标示符由字母.下划线和数字组成,且数字不能开头 注:python中的标识符是区分大小写的 命 ...
- 3d max 动作Take 001改名
问题描述 带动作的Fbx文件导入Unity之后,动作名字为Take 001,如下所示: 在max那边是没有办法改名的,只能在Unity中改名. 方法1 1. 选中动画文件,按Ctrl + D,复制一份 ...
- FAT32格式和NTFS格式区别
NTFS(Windows):支持最大分区2TB,最大文件2TB: FAT16(Windows):支持最大分区2GB,最大文件2GB: FAT32(Windows):支持最大分区128GB,最大文件4G ...
- 025k个一组翻转链表
#include "000库函数.h" struct ListNode { int val; ListNode *next; ListNode(int x) : val(x), n ...
- #005Python实验楼基本操作学习笔记
Ctrl + D 输入一个 EOF 字符来退出解释器,也可以键入 exit() 来退出解释器. 打开 Xfce 终端,键入 vim helloworld.py 来启动 Vim 并编辑 hellowor ...
- TCP三次握手与四次握手
背景描述 通过上一篇中网络模型中的IP层的介绍,我们知道网络层,可以实现两个主机之间的通信.但是这并不具体,因为,真正进行通信的实体是在主机中的进程,是一个主机中的一个进程与另外一个主机中的一个进程在 ...
- ActiveMQ的两种消息模式,主题、队列
1.开发的模式流程如下: 2.队列模式Queue 如果生产者产生了100条消息,那么两个消费同时在的话,会分工合作来接收这100条消息.就是每个消费者接收到50条来处理. 3.主题模式topic 如果 ...
- svn离线安装以及配置,管理python自动化脚本
1.使用源码安装,自己make和install,难度还挺大的,改用对应iso中的rpm安装包来安装 2.iso中的rpm包安装,会存在rpm包之间的依赖的关系 3.这种依赖关系,可以处理,仍然在iso ...