类和对象提高

程序设计与算法(三)C++面向对象程序设计-郭炜 第三周
总结整理:
目录:

      • 1.this指针
      • 2.静态成员
      • 3.成员对象和封闭类
      • 4.友元 (friends)
      • 5.常量成员函数

1.this指针

C++程序到C程序的翻译

class CCar { public: int price; void SetPrice(int p);}; void CCar::SetPrice(int p){   price = p;  } int main() { CCar car; car.SetPrice(20000); return 0; }
------------------------------------------------
struct CCar {   int price;  
}; 
void SetPrice(struct CCar * this, int p) 
{    this->price = p;    } int main()  { struct CCar car; SetPrice( & car, 20000); return 0; 
}

this指针作用
其作用就是指向成员函数所作用 的对象

非静态成员函数中可以直接使用this来代表指向该函数 作用的对象的指针

class Complex 
{public: double real, imag; void Print() {  cout << real << "," << imag ;  } Complex(double r,double i):real(r),imag(i) { } Complex AddOne()  { this->real ++;  //等价于 real ++; this->Print();    //等价于 Print return * this; } 
}; int main()  { Complex c1(1,1),c2(0,0); c2 = c1.AddOne(); //c1被修改,把c1的值赋值给c2return 0; 
} //输出 2,1
class A { int i;public: void Hello() { cout << "hello" << endl; } 
};   // void Hello(A * this ) { cout << "hello" << endl; } int main() 
{ A * p = NULL; p->Hello(); // Hello(p); 
} 
// 输出:hello--------------------------------------------
class A { int i;public: void Hello() { cout << i << "hello" << endl; } 
};   // void Hello(A * this )// { cout << this->i << "hello" << endl; } 
//this若为NULL,则出错!!   找不到空指针指向的对象的i
int main() 
{ A * p = NULL; p->Hello(); // Hello(p); 
} 
// 输出:hello

静态成员函数中不能使用 this 指针!
因为静态成员函数并不具体作用与某个对象!
因此,静态成员函数的真实的参数的个数,就是程序中写出的参数个数!
类的非静态成员函数,真实的参数比所写的参数多1,多出来的是this指针

2.静态成员

静态成员:在定义前面加了static关键字的成员

class CRectangle { private: int w, h; static int nTotalArea;  //静态成员变量 static int nTotalNumber; public: CRectangle(int w_,int h_); ~CRectangle(); static void PrintTotal();  //静态成员函数 
};

普通成员变量每个对象有各自的一份,而静态成员变 量一共就一份,为所有对象共享。
同一个类的不同的对象,普通成员变量不一样。而静态成员变量则一样
sizeof 运算符不会计算静态成员变量

class CMyclass 
{ int n; static int s;//sizeof( CMyclass ) 等于 4}; 

普通成员函数必须具体作用于某个对象,而静态成员 函数并不具体作用于某个对象。不在一个对象内部,而是放在所有对象外部,为所有对象所共享
因此静态成员不需要通过对象就能访问。

静态成员变量本质上是全局变量,哪怕一个对象都不存在,类 的静态成员变量也存在。
静态成员函数本质上是全局函数。
设置静态成员这种机制的目的是将和某些类紧密相关的全局变量和函数写到类里面,看上去像一个整体,易于维护和理解。别的类没法访问这个变量

如何访问静态成员
1) 类名::成员名
CRectangle::PrintTotal();
2) 对象名.成员名
CRectangle r; r.PrintTotal();
3) 指针->成员名
CRectangle * p = &r; p->PrintTotal(); 并不只属于到p所指向的那个对象
4) 引用.成员名
CRectangle & ref = r; int n = ref.nTotalNumber

静态成员示例
考虑一个需要随时知道矩形总数和总面积的图形 处理程序
可以用全局变量来记录总数和总面积
用静态成员将这两个变量封装进类中,就更容易 理解和维护

#include<iostream>
using namespace std; class CRectangle { private: int w, h; static int nTotalArea;  //静态成员变量 static int nTotalNumber; public: CRectangle(int w_,int h_); ~CRectangle(); static void PrintTotal();  //静态成员函数 
};
CRectangle::CRectangle(int w_,int h_) 
{ w = w_; h = h_; nTotalNumber ++; nTotalArea += w * h;    
} 
CRectangle::~CRectangle(){ nTotalNumber --; nTotalArea -= w * h; } void CRectangle::PrintTotal() { cout << nTotalNumber << "," <<   nTotalArea << endl; }int CRectangle::nTotalNumber = 0; int CRectangle::nTotalArea = 0; 
// 必须在定义类的文件中对静态成员变量进行一次说明//或初始化。否则编译能通过,链接不能通过。 int main() { CRectangle r1(3,3), r2(2,2); //cout << CRectangle::nTotalNumber; // Wrong , 私有 CRectangle::PrintTotal();r1.PrintTotal(); return 0; }//输出结果: //2,13//2,13

此CRectangle类写法, 有何缺陷?
在使用CRectangle类时,有时会调用复制构造函数 生成临时的隐藏的CRectangle对象
调用一个以CRectangle类对象作为参数的函数时,
调用一个以CRectangle类对象作为返回值的函数时
临时对象在消亡时会调用析构函数,减少nTotalNumber 和 nTotalArea的值,可是这些临时对象在生成时却没有增加 nTotalNumber 和 nTotalArea的值,因此最终可能数量小于应有的。
解决办法:为CRectangle类写一个复制构造函数


CRectangle :: CRectangle(CRectangle & r ) 
{w = r.w;   h = r.h; nTotalNumber ++; nTotalArea += w * h; 
}

在静态成员函数中,不能访问非静态成员变量, 也不能调用非静态成员函数。非静态成员函数可能需要调用非静态成员变量,那不能确定是哪一个非静态成员变量,因此不能

void CRectangle::PrintTotal() 
{ cout << w << "," << nTotalNumber << "," << nTotalArea << endl; //wrong}
CRetangle::PrintTotal(); //解释不通,w 到底是属于那个对象的?

3.成员对象和封闭类

有成员对象的类叫 封闭(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) { };int main() { CCar car(20000,17,225); return 0; }

上例中,如果 CCar类不定义构造函数, 则下面的语句会编译出错:
CCar car;
因为编译器不明白 car.tyre该如何初始化。car.engine 的初始化没问题,用 默认构造函数即可。
任何生成封闭类对象的语句,都要让编译器明白,对象中的成员对象,是如何 初始化的。
具体的做法就是:通过封闭类的构造函数的初始化列表。
成员对象初始化列表中的参数可以是任意复杂的表达式,可以包括函数,变量 ,只要表达式中的函数或变量有定义就行。

封闭类构造函数和析构函数的执行顺序
封闭类对象生成时,先执行所有对象成员的构造函数,然后才执 行封闭类的构造函数。
对象成员的构造函数调用次序和对象成员在类中的说明次序一致 ,与它们在成员初始化列表中出现的次序无关。
当封闭类的对象消亡时,先执行封闭类的析构函数,然后再执行 成员对象的析构函数。次序和构造函数的调用次序相反。

封闭类实例

#include<iostream>
using namespace std;class CTyre { public: CTyre() { cout << "CTyre contructor" << endl; } ~CTyre() { cout << "CTyre destructor" << endl; } 
};
class CEngine { public: CEngine() { cout << "CEngine contructor" << endl; } ~CEngine() { cout << "CEngine destructor" << endl; } 
}; 
class CCar
{ private: CEngine engine;  CTyre tyre; public: CCar( ) { cout << "CCar contructor" << endl; } ~CCar() { cout << "CCar destructor" << endl; } 
};int main(){ CCar car; return 0; 
}
//CEngine contructor
//CTyre contructor
//CCar contructor
//CCar destructor
//CTyre destructor
//CEngine destructor

封闭类的复制构造函数
封闭类的对象,如果是用默认复制构造函数初始化的,那么它里面包含的成员对象, 也会用复制构造函数初始化

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
**/

4.友元 (friends)

友元分为友元函数和友元类两种

1) 友元函数: 一个类的友元函数可以访问该类的私有成员.

class CCar ; //提前声明 CCar类,以便后面的CDriver类使用 
class CDriver 
{ public: void ModifyCar( CCar * pCar) ; //改装汽车 
}; 
class CCar { private: int price; friend int MostExpensiveCar( CCar cars[], int total); //声明友元 friend void CDriver::ModifyCar(CCar * pCar); //声明友元 
};
void CDriver::ModifyCar( CCar * pCar) 
{ pCar->price += 1000; //汽车改装后价值增加 
} 
int MostExpensiveCar( CCar cars[],int total) //求最贵汽车的价格 
{ int tmpMax = -1; for( int i = 0;i < total; ++i ) if( cars[i].price > tmpMax) tmpMax = cars[i].price; return tmpMax; 
} 
int main() { return 0; }

可以将一个类的成员函数(包括构造、析构函数)说明为另一个类的友元。

class B { public: void function(); 
};class A { friend void B::function();
};

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; }

友元类之间的关系不能传递,不能继承

5.常量成员函数

如果不希望某个对象的值被改变,则定义该对象的时候可以在前面加 const关键字。

class Sample 
{ private : int value; public: Sample() { } void SetValue() { } 
}; 
const Sample Obj;  // 常量对象 
Obj.SetValue ();  //错误 。常量对象只能使用构造函数、
//析构函数和有 const 说明的函数(常量方法

在类的成员函数说明后面可以加const关键字,则该成员函数成为常量 成员函数。
常量成员函数内部不能改变属性的值,也不能调用非常量成员函数


class Sample { private : int value; public: void func() { }; Sample() { } void SetValue()  const {   value = 0; // wrong func(); //wrong } 
}; const Sample Obj; Obj.SetValue (); //常量对象上可以使用常量成员函数

在定义常量成员函数和声明常量成员函数时都应该使用const 关键字。


class Sample { 
private : 
int value; 
public: 
void PrintValue()  const; 
}; 
void Sample::PrintValue()  const { 
//此处不使用const会 
//导致编译出错 
cout << value; 
} 
void Print(const Sample & o) 
{ o.PrintValue(); } 
//若 PrintValue非const则编译错    

如果一个成员函数中没有调用非常量成员函数 ,也没有修改成员变量的值,那么,最好将其 写成常量成员函数

常量成员函数的重载

两个函数,名字和参数表都一样,但是一个是const,一个不是,算重载。

#include <iostream> 
using namespace std;class CTest { private : int n; public: CTest() { n = 1 ; } int GetValue()  const  { return n ; } int GetValue() { return 2 * n ; } };int main()  {const CTest objTest1;CTest objTest2; cout << objTest1.GetValue() << "," << objTest2.GetValue() ; return 0;
}
//1,2

mutable成员变量
可以在const成员函数中修改的成员变量

class CTest  {  public:  bool GetData() const  {  m_n1++;  return m_b2;  }  private:  mutable int  m_n1;  bool m_b2;  
};

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/560954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

4)lsof linux命令,***Linux命令实时监测系统(top,htop,iotop,lsof,tcpdump,netstat,vmstat,iostat)...

摘要&#xff1a;本文总结了8个非常实用的Linux命令行性能监测工具&#xff0c;这些命令支持所有的Linux系统&#xff0c;不仅可以用于监控系统&#xff0c;还可以发现导致性能问题的原因所在。对每个系统/网络管理员来说&#xff0c;每天监测Linux系统性能是一项非常艰巨的任务…

算法竞赛入门经典 第七章 总结

目录&#xff1a; 7.1 简单枚举7.2 枚举排列7.3 子集生成 7.1 简单枚举 例题7-1 除法&#xff08;Division, UVa 725&#xff09; 输入正整数n&#xff0c;按从小到大的顺序输出所有形如abcde/fghij n的表达式&#xff0c;其中a&#xff5e;j恰好 为数字0&#xff5e…

bootstraptable 列隐藏_bootstrap中table如何隐藏列?

Bootstrap如何隐藏table中的某一列&#xff1f;下面本篇文章给大家介绍一下。有一定的参考价值&#xff0c;有需要的朋友可以参考一下&#xff0c;希望对大家有所帮助。Bootstrap隐藏table中的某一列1、利用bootstrapTable来设置要隐藏和显示的列$(function () {//初始化tableL…

华为android强刷系统下载地址,华为强刷救砖卡刷包合集下载(一)共707GB

(High Level Repair Center is forbidden)Berlin-AL10AC00B381_Android7.0_EMUI5.0_05014NVD.zip(High Level Repair Center is forbidden)GRA-CL00_C92B370_Android6.0_EMUI4.0.2_05012QKC.zipMLA-AL10C00B360_Android7.0_EMUI5.0.1_05014DHN.zipMLA-UL00_C17B170_China_联通…

线性表总结

线性表及其实现多项式的表示什么是线性表线性表的抽象数据类型描述线性表的顺序存储实现线性表的链式存储实现 线性表及其实现 多项式的表示 [例] 一元多项式及其运算 一元多项式 &#xff1a; 主要运算&#xff1a;多项式相加、相减、相乘等 【分析】如何表示多项式?…

md 生成目录 码云_搭建简易博客方案

现在大家都喜欢用markdown来写技术博客&#xff0c;这篇文章将阐述搭建支持markdown的简易博客方法。我的写作需求通过阅读本文&#xff0c;您将学会搭建满足以下条件的博客&#xff1a;博客只用书写markdown文件能支持版本控制免费&#xff0c;不需要租服务器或主机编写、部署…

mix2s android p功能,已升安卓P!网友:MIX2S才是亲儿子

原标题&#xff1a;已升安卓P&#xff01;网友&#xff1a;MIX2S才是亲儿子一直以来&#xff0c;小米在手机系统更新上都有着非常明显的优势&#xff0c;MIUI经过了多年的更新迭代&#xff0c;如今已经达到了非常不错的易用性&#xff0c;而且流畅度方面的表现更是优秀。如今小…

python爬取图片的步骤_Python爬取图片的过程分析

一、获取网页源码二、数据解析&#xff0c;得到图片的地址、部分文字作为文件名三、返回图片的二进制字节码四、保存图片文件到本地import requestsfrom lxml import etreeimport osheaders {User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_12_0) AppleWebKit/537.36…

堆栈总结

堆栈什么是堆栈堆栈的抽象数据类型描述栈的顺序存储实现 堆栈 什么是堆栈 计算机如何进行表达式求值&#xff1f; 算术表达式56/2-3*4。 正确理解&#xff1a; 56/2-3*4 53-3*4 8-3*4 8-12 -4 由两类对象构成的&#xff1a; 运算数&#xff0c;如2、3、4 运算符号…

nfc sim android8,Android NFC相关资料之MifareClassic卡(读写)

from: http://wszf.net/archives/2012/11/07/80510.html一般来说&#xff0c;给予MifareClassic的射频卡&#xff0c;一般内存大小有3种&#xff1a;1K: 16个分区(sector)&#xff0c;每个分区4个块(block)&#xff0c;每个块(block) 16个byte数据2K: 32个分区&#xff0c;每个…

android8 通知呼吸灯_Android8.0及以上的Notification

这篇文章上次修改于 702 天前&#xff0c;可能其部分内容已经发生变化&#xff0c;如有疑问可询问作者。在新版本上(Android8.0及以上)开发时&#xff0c;会遇到一些问题&#xff0c;比如&#xff0c;不显示通知&#xff0c;Notification 声音不可控&#xff0c;删除 channel 删…

harmonyos公测招募,nova为主 HarmonyOS 2.0开发者Beta公测再招募

原标题&#xff1a;nova为主 HarmonyOS 2.0开发者Beta公测再招募HarmonyOS 2.0开发者Beta公测招募将开启第二期&#xff0c;本次公测活动主要针对的机型是华为nova系列。活动报名时间为5月9日-5月17日。【PChome手机频道资讯报道】华为方面在4月份开启了HarmonyOS 2.0开发者Bet…

队列总结

什么是队列 队列(Queue)&#xff1a;具有一定操作约束的线性表 插入和删除操作&#xff1a;只能在一端插入&#xff0c;而在另一端删除 数据插入&#xff1a;入队列&#xff08;AddQ&#xff09; 数据删除&#xff1a;出队列&#xff08;DeleteQ&#xff09; 先来先服务 先…

python连接mongodb进行查询_Python中的MongoDB基本操作:连接、查询实例

这篇文章主要介绍了Python中的MongoDB基本操作&#xff1a;连接、查询实例,本文直接给出操作示例代码,需要的朋友可以参考下MongoDB是一个基于分布式文件存储的数据库。由C语言编写。旨在为WEB应用提供可护展的高性能数据存储解决方案。它的特点是高性能、易部署、易使用&#…

D P- 免费馅饼

题目 都说天上不会掉馅饼&#xff0c;但有一天gameboy正走在回家的小径上&#xff0c;忽然天上掉下大把大把的馅饼。说来gameboy的人品实在是太好了&#xff0c;这馅饼别处都不掉&#xff0c;就掉落在他身旁的10米范围内。馅饼如果掉在了地上当然就不能吃了&#xff0c;所以ga…

android+录像中截图软件下载,录屏截图大师app

录屏截图大师app是一款专业录屏软件&#xff0c;不少用户可能会有使用手机录屏的需求&#xff0c;尤其是在手机内置没有录屏功能的时候&#xff0c;这款软件就非常值得大家考虑&#xff0c;支持自定义设置录屏的大小和画质&#xff0c;还没有水印&#xff0c;还支持后期的简单编…

python随机函数笔记_Python笔记__random

random模块提供了随机数相关的一些函数&#xff0c;所有函数都绑定在一个random.Random类的实例上&#xff0c;所以&#xff0c;你可以直接用模块级的函数random.xxx()&#xff0c;也可以random.Random().xxx()。random.random(): 随机生成一个[0.0, 1.0)范围内的浮点数。是下面…

一加桌面3.0 android8,一加手机XRemix6.0安卓8.1.0Beta2.0定制本地化增强适配归属农历等...

制作者&#xff1a;moonlight-roms基于版本&#xff1a;remix最新安卓8.1.0代码适合机型&#xff1a;一加手机X双网版/全网通版/E1001/E1003等/onyx注意事项&#xff1a;1.开机后语言设置&#xff1a;Settings-system-languageandinput-添加一个中文需要并拖动到第一行设置为默…

震惊!Fibonacci Again

题目 There are another kind of Fibonacci numbers: F(0) 7, F(1) 11, F(n) F(n-1) F(n-2) (n>2). Input Input consists of a sequence of lines, each containing an integer n. (n < 1,000,000). Output Print the word “yes” if 3 divide evenly into …

jumpserver 使用教程_Jumpserver之快速入门

一&#xff0c;系统设置1.1基本设置修改 url 的"localhost"为你的实际 url 地址, 否则邮件收到的地址将为"localhost" 也无法创建新用户1.2邮件设置1.3终端设置保持默认设置即可1.4安全设置根据需要设置二.用户管理2.1创建jumpserver用户#点击页面左侧&quo…