C++面向对象程序设计课程笔记(第三周)
第一节 this指针
1.C++程序到C程序的翻译
图1 从C++到C
C++中的class在C语言中并不存在,因此可以用struct(结构体)来代替,成员变量也可以直接用域来代替,但是类中的成员函数却无法在C语言中直接表示,所以只能把SetPrice设置为全局函数。由于是全局函数,为了能让其使用结构体内的数据,故在SetPrice中增加了一个参数struct CCar *this,这样就可以在函数体中把p的值传递给结构体中的price,实现了跟成员函数一样的功能,同理,在main()中SetPrice函数执行也得把car的地址传递过去。
故,this的作用就是指向成员函数所作用的对象。
2.this指针作用
(1)非静态成员函数中可以直接使用this来代表指向该函数作用的对象的指针。
图2 this指针作用
在main()函数中,首先对对象c1执行了AddOne()函数,然后开始执行AddOne(),对c1中的real加1,然后执行对c1的Print()函数,这之后,返回一个this指针所指向对Complex对象(即c1)给c2。
对this指针再加深一个理解,如下例:
class A{int i;public:void Hello(){cout<<“”Hello”<<endl;}};int main(){A *p=NULL;p->Hello();}
系统会报错吗?答案是否定的,并且输出Hello。原因在于,虽然我们看着这个*p指向的空,但是实际上,由于C++在转换成C语言的时候,成员函数会被转换成全局函数并增加一个this指针的参数,即变为了
void Hello(A *this){cout <<”Hello”<<endl;
主函数中的p->Hello();也变成了Hello(p);
因此就算p为空指针,在这里传递给全局函数后并没有用到p做任何输出,所以直接输出了Hello。但如果我们在这个函数的输出时用到了成员变量i,那么成员函数在变换到全局函数的时候再来执行就用到了这个this所指向的对象,而此时this指向的p为空,所以报错。
静态成员函数不能使用this指针,因为静态成员函数并不具体作用于某个对象,因此静态成员函数的真是的参数的个数,就是程序中写出的参数个数!
第二节 静态成员变量
1.静态成员基本概念
在定义前面加了static关键字的成员,称为静态成员。静态成员包括静态成员变量和静态成员函数两种。
普通成员变量每个对象有各自的一份,而静态成员变量一共就一份,为所有对象共享。
sizeof运算符在计算类的大小的时候不会计算静态成员变量。
普通成员函数必须具体作用于某个对象,而静态成员函数并不具体作用于某个对象。
因此静态成员不需要通过对象就能访问。
静态成员变量本质上是全局变量!!!
静态成员函数本质上是全局函数!!!
设置静态成员的机制是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一根整体,容易维护和理解。
2.如何访问静态成员
(1)类名::成员名
例如CRectangle::PrintTotal();
(2)对象名.成员名
例如CRectangle r; r.PrintTotal();
(3)指针->成员名
CRectangle *p=&r;p->PrintTotal();
(4)引用.成员名
CRectangle &ref =r; int n = ref.nTotalNumber;
必须在定义类的文件中对静态成员变量进行一次说明或初始化,否则编译能通过,链接不能通过。
在静态成员函数中,不能访问非静态成员变量,也不能调用非静态成员函数。
如下所示的写法,存在缺陷。
CRectangle::CRectangle(int w_,h_) {w = w_;h = h_;nTotalNumber++;nTotalArea += w* h;}CRectangle::~CRectangle(){nTotalNumber–;nTotalArea -= w*h;}void CRectangle::PrintTotal(){cout<<nTotalNumber<<“,”<<nTotalArea<<endl;}
在使用CRectangle类时,有时会调用复制构造函数生成临时的隐藏的CRectangle对象,比如:①我们调用了一个以CRectangle类对象作为参数的函数;②调用一个以CRectangle类对象作为返回值的函数。这个时候就如前面介绍复制构造函数时所说,会产生一个隐藏的临时对象(此函数没写复制构造函数,因此就算直接复制值过去,并没有执行Crectangle(int w_,int h_)),而这个临时对象在消亡的时候会调用析构函数,减少了nTotalNumber和nTotalArea的值,而它们这些对象在生成时却没有增加这两个值,由于这两个值是静态成员变量,所以实际上这两个值是减少了。
解决方案很显然就算写一个复制构造函数:
CRectangle::CRectangle(CRectangle &r){w = r.w;h=r.h;nTotalNumber ++;nTotalArea += w*h;}
第三节 成员对象和封闭类
1.基本概念
有成员对象的类交封闭(enclosing)类。
有一个类的成员是其它类的对象,被称为成员对象。
如下例程:
class CTyre{private:int radius;int width;public:CTyre(int r int w):radius(r),width(w){}//初始化列表,可以为每一个成员变量提供一个初始值。};class CEngine{};class CCar{//封闭类private:int price;Ctyre tyre;//成员对象CEngine engine;//成员对象public:CCar(int p, int tr,int tw);};CCar::CCar(int p,int tr,int w):price(p),tyre(tr,w)//engine使用无参构造函数构造{};int main(){CCar car(20000,17,225);return 0;}
在这个例子,如果CCar类不定义构造函数,则CCar car;这个语句会报错,因为编译器不明白car.tyre该如何初始化。
任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象是如何初始化的。
具体做法是:通过封闭类的构造函数的初始化列表进行。
成员对象初始化列表中的参数可以是任意复杂的表达式,可以包括函数、变量,只要表达式中的函数或变量有定义就行。
2.封闭类构造函数和析构函数的执行顺序
(1)封闭类对象生成时,先执行所有对象成员的构造函数,然后才执行封闭类的构造函数;
(2)对象成员的构造函数调用次序和对象成员在类中的说明次序一致,与它们在成员初始化列表中出现的次序无关;
(3)当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行成员对象的析构函数。次序和构造函数的调用次序相反。
3.封闭类的复制构造函数
封闭类的对象,如果是用默认复制构造函数初始化的,那么它里面包含的成员对象,也会用复制构造函数初始化。
例如:
Class A{public:A(){cout<<“default”<<endl;}A(A&a){cout<<“copy”<<endl;}};class B{A a;};int main(){B b1,b2(b1);return 0;}
输出: default copy
说明b2.a是用类A的复制构造函数初始化的,而且调用复制构造函数的实参就是b1.a。
第四节 友元(friends)
友元分为友元函数和友元类两种。
1.友元函数
一个类的友元函数可以访问该类的私有成员(这说明友元函数不是这个类的成员函数)
可以将一个类的成员函数(包括构造、析构函数)说明为另一个类的友元。
Class B{public:void function();};Class A{friend void B::function();};
这就代表function()可以访问A里面的私有成员了。
2.友元类
如果A是B的友元类,那么A的成员函数可以访问B的私有成员。
Class CCar{private:int price;friend class CDriver;//声明CDriver为友元类};class CDriver{public:CCar myCar;void ModifyCar(){myCar.price += 1000;//因为CDriver是CCar的友元类,故可以访问其私有成员}};int main(){return 0;}
友元类之间的关系不能传递,不能继承!
第三节 常量对象、常量成员函数和常引用
1.常量成员函数
如果不希望某个对象值被改变,则定义该对象的时候可以在前面加const关键词。例如:
class Sample{private:int value;public:Sample(){}void SetValue(){}};const Sample Obj;//常量对象Obj.SetValue();//错误。常量对象只能使用构造函数、析构函数和右const说明的函数(const方法)
在类的成员函数说明后面加const关键字,则该成员函数为常量成员函数。常量成员函数执行期间不应修改其作用的对象。因此,在常量成员函数中不能修改成员变量的值(静态成员变量除外),也不能调用同类的非常量成员函数(静态成员函数除外)。
如下:
class Sample{public:int value;void func(){};Sample(){}void GetValue() const;};void Sample::GetValue() const{value = 0;//wrongfunc();//wrong}int main(){const Sample o;o.value = 100;//err常量对象不可被修改o.func();//常量对象上面不能执行非常量成员函数o.GetValue();//OK常量对象可以执行常量成员函数return 0;}
需要注意,在Dev C++中,要为Sameple类编写无参构造函数才可以,在VS中不需要。
2.常量成员函数的重载
两个成员函数,名字和参数表都一样,但是一个是const,一个不是,算重载。
3.常引用
引用前面加const称为常引用。不能通过常引用修改其引用的变量。
可以用对象的引用作为参数,如:
class Sample{};void PrintfObj(Sample & o){}
对象引用作为函数的参数有一定风险性,若函数中不小心修改了形参o,则实参也跟着变。为了避免这个问题,我们可以用对象的常引用作为参数,这样就能确保不会出现无意中更改o值的语句了。
class Sample{};void PrintfObj(const Sample & o){}
C++面向对象程序设计课程笔记(第三周)相关推荐
- 干货|机器学习零基础?不要怕,吴恩达课程笔记第三周!逻辑回归与正则
吴恩达Coursera机器学习课系列笔记 课程笔记|吴恩达Coursera机器学习 Week1 笔记-机器学习基础 干货|机器学习零基础?不要怕,吴恩达机器学习课程笔记2-多元线性回归 1 Logis ...
- 面向对象程序设计课程进度条
面向对象程序设计课程进度条 周次 (阅读/编写)代码行数 发布微博量/博客评论数量 课堂/课余学习时间(小时) 最满意的编程任务 第一周 42/25 1/0 4/3 乘法表实验 第二周 150/100 ...
- C++《面向对象程序设计课程设计》
C++<面向对象程序设计课程设计> <面向对象程序设计课程设计>课程说明 适用专业:计算机科学与技术 课程周数:5周 一.根据计算机科学与技术专业人才培养方案制订. (一)课程 ...
- C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序
C#面向对象程序设计课程实验二: 实验名称:Windows 窗体程序 实验内容:Windows 窗体程序 一.实验目的及要求 二.实验环境 三.实验内容与步骤 一.设计简单的计算器 3.1.实验内容 ...
- C#面向对象程序设计课程实验五:实验名称:C#面向对象技术
C#面向对象程序设计课程实验五:实验名称:C#面向对象技术 实验内容:C#面向对象技术 一. 实验目的及要求 二.实验环境 三.实验内容与步骤 3.1.实验内容:测试类,实现多态 3.2.实验步骤 3 ...
- C#面向对象程序设计课程实验一:实验名称:C#语言基础、程序流程控制
C#面向对象程序设计课程实验一:实验名称:C#语言基础.程序流程控制 实验内容:C#语言基础.程序流程控制 一. 实验目的 二.实验环境 三.实验内容 四.实验总结 实验内容:C#语言基础.程序流程控 ...
- java计算机毕业设计面向对象程序设计课程网站源码+系统+mysql数据库+lw文档
java计算机毕业设计面向对象程序设计课程网站源码+系统+mysql数据库+lw文档 java计算机毕业设计面向对象程序设计课程网站源码+系统+mysql数据库+lw文档 本源码技术栈: 项目架构:B ...
- 面向对象程序设计·学习笔记(1/2)
面向对象程序设计·学习笔记(1/2) 前言 第1章 类与对象 1.1 用类制造对象 1.2 定义类 1.3 成员变量和成员函数 1.4 对象初始化 第2章 对象交互 2.1 对象交互 2.2 访问属性 ...
- 面向对象程序设计——Java语言 第3周编程题 查找里程(10分)
面向对象程序设计--Java语言 第3周编程题 查找里程(10分) 题目内容 下图为国内主要城市之间的公路里程: 你的程序要读入这样的一张表,然后,根据输入的两个城市的名称,给出这两个城市之间的里程. ...
最新文章
- apache+php为什么不报错
- linux 卸载java jdk1.6_Linux/CentOS 卸载系统原装jdk1.4 和安装jdk1.6.1
- linux常用命令记录
- python字符串截取拼接_Python字符串拼接、截取及替换方法总结分析
- 通过C学Python(3)列表的常用方法
- python数据科学入门_干货!小白入门Python数据科学全教程
- dplyr | 数据处理函数的功能速查!dplyr包中的十类操作函数汇总(下篇)
- 春日 [宋] 王安石
- LNMP下Redis介绍以及安装(Linux)
- Linux下安装zookeeper集群,以及在window用dubbo和代码测试
- JavaScript 函数参数默认值
- 在Eclipse中使用JUnit5进行单元测试
- 扩展城市信道etu模型matlab仿真,信道估计
- 云计算ACP认证考试题库之101-200
- win7安装OneNote
- LeetCode 430. Flatten a Multilevel Doubly Linked List【链表/DFS/递归/迭代】中等
- 视频处理VideoCapture类---OpenCV-Python开发指南(38)
- Android项目:基于Android手机校园外卖订餐系统(计算机毕业设计)
- python程序运行时间的几种分析方法
- face_recognition模块方法集合