C++程序设计(二)
1. 类
class CRectangle { public: int w, h; void Init( int w_, int h_ ) { w = w_; h = h_; } int Area() { return w * h; } int Perimeter() { * ( w + h ); } }; //必须有分号
int main() { int w, h; CRectangle r; //r是一个对象 cin >> w >> h; r.Init(w, h); cout << r.Area() << endl << r. Perimeter(); ; }
类定义的变量 -> 类的实例 -> “对象”
对象的大小 = 所有成员变量的大小之和。E.g. CRectangle类的对象, sizeof(CRectangle) = 8
对象之间可以用 ‘=’ 进行赋值
- 访问类的成员变量和成员函数
用法1: 对象名.成员名CRectangle r1, r2; r1.w = ; r2.Init(,);
用法2: 指针->成员名
CRectangle r1, r2; CRectangle * p1 = & r1; CRectangle * p2 = & r2; p1->w = ; p2->Init(,); //Init作用在p2指向的对象上
用法3: 引用名.成员名
CRectangle r2; CRectangle & rr = r2; rr.w = ; rr.Init(,); //rr的值变了,r2的值也变
- 类的成员函数的另一种写法
class CRectangle { public: int w, h; int Area(); //成员函数仅在此处声明 int Perimeter() ; void Init( int w_, int h_ ); };
int CRectangle::Area() { return w * h; } int CRectangle::Perimeter() { * ( w + h ); } void CRectangle::Init( int w, int h) { this->w = w; this->h = h;
}
2. 类成员的可访问范围
private: 指定私有成员, 只能在成员函数内被访问
public: 指定公有成员, 可以在任何地方被访问
protected:指定保护成员
缺省为私有成员!
对象成员的访问权限:
类的成员函数内部, 可以访问:当前对象的全部属性, 函数; 同类其它对象的全部属性, 函数
类的成员函数以外的地方只能够访问该类对象的公有成员
class CEmployee { private: ]; //名字 public : int salary; //工资 void setName(char * name); void getName(char * name); void averageSalary(CEmployee e1,CEmployee e2); }; void CEmployee::setName( char * name) { strcpy( szName, name); //ok } void CEmployee::getName( char * name) { strcpy( name, szName); //ok } void CEmployee::averageSalary(CEmployee e1,CEmployee e2){ salary = (e1.salary + e2.salary )/; } int main(){ CEmployee e; strcpy(e.szName,"Tom1234567889"); //编译错, 不能访问私有成员 e.setName( "Tom"); // ok e.salary = ; //ok ; }
设置私有成员的目的:强制对成员变量的访问一定要通过成员函数进行
设置私有成员的机制 -- 隐藏
2. 构造函数
成员函数的一种:
- 名字与类名相同,可以有参数,不能有返回值(void也不行)
- 作用是对对象进行初始化,如给成员变量赋初值
- 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
- 默认构造函数无参数,不做任何操作
- 如果定义了构造函数,则编译器不生成默认的无参数的构造函数
- 对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数
- 一个类可以有多个构造函数,参数个数或类型不同
class Complex { private : double real, imag; public: void Set( double r, double i); }; //编译器自动生成默认构造函数 Complex c1; //默认构造函数被调用 Complex * pc = new Complex; //默认构造函数被调用
class Complex { private : double real, imag; public: Complex( ); }; Complex::Complex( double r, double i) { real = r; imag = i; } Complex c1; // error, 缺少构造函数的参数 Complex * pc = new Complex; // error, 没有参数 Complex c1(); // OK Complex c1(,), c2(,); Complex * pc = ,);
class Complex { private : double real, imag; public: void Set( double r, double i ); Complex(double r, double i ); Complex (double r ); Complex (Complex c1, Complex c2); }; Complex::Complex(double r, double i) { real = r; imag = i; } Complex::Complex(double r){ real = r; imag = ; } Complex::Complex (Complex c1, Complex c2){ real = c1.real+c2.real; imag = c1.imag+c2.imag; } Complex c1() , c2(,), c3(c1,c2);
构造函数在数组中使用
class CSample { int x; public: CSample() { cout << "Constructor 1 Called" << endl; } CSample(int n) { x = n; cout << "Constructor 2 Called" << endl; } }; int main(){ CSample array1[]; cout << "step1"<<endl; CSample array2[] = {,}; cout << "step2"<<endl; CSample array3[] = {}; cout << "step3"<<endl; CSample * array4 = ]; delete []array4; ; }
输出: Constructor Called Constructor Called step1 Constructor Called Constructor Called step2 Constructor Called Constructor Called step3 Constructor Called Constructor Called
class Test { public: Test( int n) { } //(1) Test( int n, int m) { } //(2) Test() { } //(3) }; Test array1[] = { , Test(,) }; // 三个元素分别用(1),(2),(3)初始化 Test array2[] = { Test(,), Test(,) , }; // 三个元素分别用(2),(2),(1)初始化 Test * pArray[] = { ), ,) }; //两个元素分别用(1),(2) 初始化
3. 内联成员函数
- inline + 成员函数
- 成员函数声明时便定义时,自动成为内联函数
4. 成员函数的重载及参数缺省
#include <iostream> using namespace std; class Location { private : int x, y; public: void init( int x = 0 , int y = 0 ); void valueX( int val ) { x = val ; } int valueX() { return x; } }; void Location::init( int X, int Y){ x = X; y = Y; } int main() { Location A; A.init(); A.valueX(); cout << A.valueX(); ; }
4. 复制构造函数
- 只有一个参数,即对同类对象的引用。
- 形如 X::X( X& )或X::X(const X &), 二者选一,后者能以常量对象作为参数
- 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
- 如果定义的自己的复制构造函数, 则默认的复制构造函数不存在。
class Complex { public : double real,imag; Complex(){ } Complex( const Complex & c ) { real = c.real; imag = c.imag; cout << “Copy Constructor called”; } }; Complex c1; Complex c2(c1);//调用自己定义的复制构造函数,输出 Copy Constructor called
复制构造函数起作用的三种情况
1)当用一个对象去初始化同类的另一个对象时。
2)如果某函数有一个参数是类 A 的对象, 那么该函数被调用时,类A的复制构造函数将被调用。
3) 如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用.
5. 类型转换构造函数
目的:实现类型的自动转换
特点:只有一个参数,不是复制构造函数
当使用类型转换构造函数的时候,编译器会自动调用这个转换构造函数,建立一个临时对象/临时变量。
class Complex { public: double real, imag; Complex( int i ) { //类型转换构造函数 cout << “IntConstructor called” << endl; real = i; imag = ; } Complex( double r, double i ){ real = r; imag = i; } }; int main () { Complex c1(, ); Complex c2 = ; c1 = ; // 9被自动转换成一个临时Complex对象 cout << c1.real << "," << c1.imag << endl; ; }
6. 析构函数
成员函数的一种
- 名字与类名相同,在前面加‘~’
- 没有参数和返回值
- 一个类最多只有一个析构函数
- 对象消亡时被自动调用
- 定义类时没写析构函数, 则编译器生成缺省析构函数(不涉及释放用户申请的内存释放等清理工作)
定义了析构函数, 则编译器不生成缺省析构函数
// 对象数组生命期结束时, 对象数组的每个元素的析构函数都会被调用 class Ctest { public: ~Ctest() { cout<< "destructor called" << endl; } }; int main () { Ctest array[]; cout << "End Main" << endl; ; }
delete 运算导致析构函数调用 Ctest * pTest; pTest = new Ctest; //构造函数调用 delete pTest; //析构函数调用 ------------------------------------------------------------------ pTest = ]; //构造函数调用3次 delete [] pTest; //析构函数调用3次
构造函数和析构函数 调用时机的例题
class Demo { int id; public: Demo( int i ){ id = i; cout << “id=” << id << “ Constructed” << endl; } ~Demo(){ cout << “id=” << id << “ Destructed” << endl; } }; 输出: Demo d1(); id=1 Constructed void Func(){ id=4 Constructed ); id=6 Constructed Demo d3(); id=6 Destructed cout << “Func” << endl; main } id=5 Constructed int main (){ id=5 Destructed Demo d4(); id=2 Constructed d4 = ; id=3 Constructed cout << “main” << endl; Func { Demo d5(); } id=3 Destructed Func(); main ends cout << “main ends” << endl; id=6 Destructed ; id=2 Destructed } id=1 Destructed
7. 静态成员变量和静态成员函数
静态成员:在说明前面加了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 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(CRectangle & r ) {
w = r.w; h = r.h; nTotalNumber ++; nTotalArea += w * h;
}
CRectangle::~CRectangle() { nTotalNumber --; nTotalArea -= w * h; } void CRectangle::PrintTotal() { cout << nTotalNumber << "," << nTotalArea << endl; } ; ; // 必须在定义类的文件中对静态成员变量进行一次说明或初始化。否则编译能通过,链接不能通过。 int main(){ CRectangle r1(,), r2(,); //cout << CRectangle::nTotalNumber; // Wrong , 私有 CRectangle::PrintTotal(); r1.PrintTotal(); ; }
输出结果: , ,
8. 成员对象和封闭类
成员对象: 一个类的成员变量是另一个类的对象,包含 成员对象 的类叫 封闭类 (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(,,); ; }
定义封闭类的构造函数时, 添加初始化列表:
类名::构造函数(参数表):成员变量1(参数表), 成员变量2(参数表), … { … }
调用顺序
当封闭类对象生成时,
•S1: 执行所有成员对象 的构造函数
•S2: 执行 封闭类 的构造函数
成员对象的构造函数调用顺序
•和成员对象在类中的声明顺序一致
•与在成员初始化列表中出现的顺序无关
当封闭类的对象消亡时,
•S1: 先执行 封闭类 的析构函数
•S2: 执行 成员对象 的析构函数
析构函数顺序和构造函数的调用顺序相反
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; ; }
程序的输出结果是: CEngine contructor CTyre contructor CCar contructor CCar destructor CTyre destructor CEngine destructor
9. 友元
一个类的友元函数可以访问该类的私有成员
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 += ; //汽车改装后价值增加 } int MostExpensiveCar( CCar cars[], int total) //求最贵汽车的价格 { ; ; i < total; ++i ) if( cars[i].price > tmpMax) tmpMax = cars[i].price; return tmpMax; } int main(){ ; }
将一个类的成员函数(包括构造, 析构函数)声明为另一个类的友元
class B { public: void function(); }; class A { friend void B::function(); };
A是B的友元类 则A的成员函数可以访问B的私有成员
class CCar { private: int price; friend class CDriver; //声明CDriver为友元类 }; class CDriver { public: CCar myCar; void ModifyCar() { //改装汽车 myCar.price += ; // CDriver是CCar的友元类可以访问其私有成员 } }; int main() { ; }
注意:友元类之间的关系不能传递, 不能继承
10. 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(,),c2(,); c2 = c1.AddOne(); ; } //输出 2,1
静态成员函数中不能使用 this 指针!
因为静态成员函数并不具体作用与某个对象!
因此,静态成员函数的真实的参数的个数,就是程序中写出的参数个数!
C++程序设计(二)的更多相关文章
- JavaScript高级程序设计(二):在HTML中使用JavaScript
一.使用<script>元素 1.<script>元素定义了6个属性: async:可选.表示应该立即下载脚本,但不应该妨碍页面中的其他操作,比如下载其他资源或等待加载其他脚本 ...
- python基础16 ----面向对象程序设计二
一.继承与派生 1.继承的定义:继承是一种创建新类的方式,即在类中提取共同的部分创建出一个类,这样的类称为父类,也可称为基类和超类,新建的类称为派生类或子类. 2.单继承:就相当于子类继承了一个父类. ...
- CUDA程序设计(二)
算法设计:直方图统计 直方图频数统计,也可以看成一个字典Hash计数.用处不是很多,但是涉及CUDA核心操作:全局内存.共享内存.原子函数. 1.1 基本串行算法 这只是一个C语言练习题. #def ...
- javascript 高级程序设计 二
这里我们直接进入主题: 在JS刚刚开始的时候,必须面临一个问题,那就是如何使的JS的加载和执行不会影响web核心语言HTML的展示效果,和HTML和谐共存. 在这个背景下<script>标 ...
- 实验7 shell程序设计二(1)
编写一个shell过程完成如下功能(必须在脚本中使用函数)1.程序接收3个参数:$1/$2和$3,合并两个文件$1/$2为$3,并显示,三个文件均为文本文件.2.如果文件$3不存在,那么先报告缺少$3 ...
- Linux命令(十一)——Shell程序设计二(循环控制语句)
1.if语句 (1)两路分支的if语句 (2)多路条件判断分支的if语句 2.测试语句 (1)文件测试 (2)字符串测试 (3)数值测试 (4)用逻辑操作符进行组合的测试语句 3.case语句 4.f ...
- 周会材料:高并发程序设计<二>
第三章 JDK并发包https://www.cnblogs.com/sean-zeng/p/11957569.html JDK内部提供了大量实用的API和框架.本章主要介绍这些JDK内部功能,主要分为 ...
- 2017-2018-2 20165206 实验二《Java面向对象程序设计》实验报告
2017-2018-2 20165206 实验二<Java面向对象程序设计>实验报告 一.实验报告封面 课程:Java程序设计 班级:1652班 姓名:韩啸 学号:20165206 指导教 ...
- 20165323 实验二 Java面向对象程序设计
一.实验报告封面 课程:Java程序设计 班级:1653班 姓名:杨金川 学号:20165323 指导教师:娄嘉鹏 实验日期:2018年4月16日 实验时间:13:45 - 15:25 实验序号:二 ...
- Java 多线程程序设计
课程 Java面向对象程序设计 一.实验目的 掌握多线程程序设计 二.实验环境 1.微型计算机一台 2.WINDOWS操作系统,Java SDK,Eclipse开发环境 三.实验内容 1.Java有 ...
随机推荐
- 在windows和linux下如何查看80端口占用情况?是被哪个进程占用?如何终止等
一.在windows下如何查看80端口占用情况?是被哪个进程占用?如何终止等 这里主要是用到windows下的DOS工具,点击"开始"--"运行",输入&quo ...
- HDU 2851 (最短路)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2851 题目大意:给出N条路径,M个终点(是路径的编号) .重合的路径才算连通的,且路径是单向的.每条路 ...
- android 内部缓存器(手机自带的存储空间中的当前包文件的路径)
关于Context中: 1. getCacheDir()方法用于获取/data/data/<application package>/cache目录 2. getFilesDir()方法用 ...
- 自己收集原生js-2014-2-15
function testforbtn(event){ alert(window.EventUtil.getEventTarget(window.EventUtil.getEvent( event)) ...
- hdu1232 并查集
1. hdu1232 2.链接:http://acm.hdu.edu.cn/showproblem.php?pid=1232 3.总结:简单并查集 #include<iostream> # ...
- FS210开发板上Qt4.7.0移植过程
作者:冯老师,华清远见嵌入式学院讲师. 1. 搭建Qt开发环境平台 1.开发环境:ubuntu 12.04 2.交叉编译链:arm-cortex_a8-linux-gnueabi 3.开发板:FS21 ...
- 20145330《Java程序设计》第四周学习总结
20145330<Java程序设计>第四周学习总结 一周两章新知识的自学与理解真的是很考验和锻炼我们,也对前面几章我们的学习进行了检测,遇到忘记和不懂的知识就再复习前面的,如此巩固也让我对 ...
- CentOS转的服务器磁盘规划
我的服务器是500G.最重要的是/var分区一定要大(不论postfix邮件,还是LAMP的WEB 服务器等).最好是400G以上.具体的/boot 只要100M就足够了.下面是我的分区方案:硬盘50 ...
- php 实现推技术comet(转)
实现实时通信一般有两种方式:socket或comet.socket是比较好的解决方案,问题在于不是所有的浏览器都兼容,服务器端实现起来也稍微有点麻烦.相比之下,comet(基于HTTP长连接的&quo ...
- Maven3路程(一)用Maven创建第一个web项目(2)
工具/原料 Windows 系统 JDK 1.5 及以上版本 Maven 3.0 及以上版本 方法/步骤 1 首先检查Eclipse是否已经添加的Maven插件,打开Eclipse, 依次选择 &qu ...