C++实例——第四章

进入面向对象的程序设计了
会写得仔细一点

类和对象的定义(类是同一类对象的抽象)

定义类

class 类名称
{
	public:
		公有成员(外部接口)
	private:
		私有成员
	protected:
		保护型成员
};

类内初始化
例4-1 钟表类

#include <iostream>
using namespace std;
//类的定义
class Clock{
public:
	void setTime(int newH = 0, int newM = 0, int newS = 0);
	void showTime();
private:
	int hour = 0, minute = 0, second = 0;//类内初始值
};
//成员函数的实现(要写上类名和作用域限定)
void Clock::setTime(int newH, int newM, int newS){
	hour = newH;
	minute = newM;
	second = newS;
}
void Clock::showTime(){
	cout<<hour<<":"<<minute<<":"<<second;
}
//对象的使用
int main(){
	Clock myClock; //使用类的实例
	myClock.setTime(8,30,30);
	myClock.showTime();
	return 0;
}

定义对象

类名 对象名;
Clock myClock;

访问

类成员之间直接用成员们互相访问
类外访问成员使用“对象名.成员名”方式访问public成员

类中定义成员函数

在类中声明函数的原型
可以在类外给出函数体实现,并在函数名前使用类名加以限定!
也可以直接在类中给出函数体定义,形成内联成员函数(必须充分简单)
在类里声明成员函数,允许声明重载函数和带默认参数值的函数
面向对象程序的基本特点

内联成员函数——为了提高运行效率

不应该有switch语句和循环语句
有两种方式:
1.将函数体放在类的声明中
2.在类中只声明函数的原型,在类外实现函数体使用inline关键字

抽象实例——钟表

数据抽象(属性)
int hour, int minute, int second
代码抽象(功能)
setTime(), showTime()

class Clock{
	public://对外访问接口
		void setTime(int newH, int newM, int newS);
		void showTime();
	public://只允许本类函数访问(隐藏在类的内部)可以授权第五章
		int hour, minute, second;
};

面向对象的特点:
1.抽象(抽象的实现:类)
2.封装(实现:类声明中的{})
3.继承(已有类扩展形成新的类)第七章
4.多态(减少标识符个数,使用类更方便)第八章

构造函数(类中的特殊函数,对类的对象初始化)

希望将Clock类对象初始时间设为0:0:0
构造函数的形式

函数名与类名相同
不能定义返回值类型,也不能有return语句
可以有形式参数,可以是内联函数,可以重载,可以带默认参数值

  • 构造函数在对象创建时被自动调用
  • 调用时可以不需要实参的叫默认构造函数
  • 如果程序中未定义构造函数,编译器将自动生成默认构造函数
    • 如果类内定义了成员的初始值,则使用类内定义的初始值
    • 如果没有,则以默认方式初始化(基本类型的数据默认初始化的值是不确定的)
  • 如果定义了构造函数,依然希望编译器生成默认构造函数,使用default关键字
class Clock{
	public:
		Clock() = default;//指示编译器提供默认构造函数
		Clock(int newH, int newM, int newS);
	private:
		int hour, minute,second;
	};

定义和使用构造函数

class Clock{
public:
	Clock(int newH, int newM, int newS);//构造函数
	Clock();//默认构造函数(经验)
	void setTime(int newH, int newM, int newS);
	void showTime();
private:
	int hour, minute, second;
};
//构造函数的实现:
Clock::Clock(int newH, int newM, int newS):
	hour(newH), minute(newM), second(newS){
	}//初始化列表,比赋值表达式的效率高
Clock::Clock():hour(0),minute(0),second(0){}//默认构造函数
//其它函数实现同例4_1

int main(){
	Clock c(0,0,0);//自动调用构造函数
	c.showTime();
	return 0;
}
int main(){
	Clock c1(8,10,0);//调用有参数的构造函数(执行时会匹配到第一个构造函数)
	Clock c2;//调用无参数的构造函数(没给实参表,调用无参数的就是第二个)
	c.showTime();
	c2.showTime();
	return 0;
}

F10:进入主函数 F11:单步执行

回顾Clock类的两个构造函数:

Clock(int newH, int newM, int newS):
	hour(newH), minute(newM), second(newS){ //构造函数
}
Clock::Clock():hour(0),minute(0),second(0) //默认构造函数

第一个是用参数表里的参数,第二个是全用0初始化,可以不必要写两个代码

委托构造函数 使用类的其他构造函数执行初始化过程——保持代码实现的一致性

Clock(int newH, int newM, int newS):
hour(newH),minute(newM),second(newS){
}
Clock():Clock(0,0,0)//无参数的构造函数调用了有参数的,将默认的三个0传给有参数的构造函数

复制构造函数(用已经存在的对象初始化新对象)第六章

形参为本类对象的引用

class 类名{
public:
类名 (形参);//构造函数
类名 (const 类名& 对象名);//复制构造函数
//...
};
类名::(const 类名 &对象名)//复制构造函数的实现
{  函数体  }
  • 没定义生成默认的复制构造函数
    执行的功能是:用初始值对象的每个数据成员,初始化将要建立的对象的对应数据成员
  • 不希望对象被复制构造
    C++98做法是:将复制构造函数声明为private,并且不提供函数的实现
    C++11做法是:用=delete指示编译器
class Point{
public:
	Point(int xx=0, int yy=0){x = xx; y == yy;} //构造函数,内联
	Point(const Point& p) = delete;//指示编译器不生成默认复制构造函数
private:
	int x,y;//私有数据
};

例4-2 Point 类的完整程序

//4_2.cpp
#include <iostream>
using namespace std;

class Point{                  //Point类的定义
public:                       //外部接口
	Point(int xx=0, int yy=0){//构造函数
		x=xx;
		y=yy;
	}
	Point(Point &p);         //复制构造函数
	int getX(){
		return x;
	}
	int getY(){
		return y;
	}
private:
	int x,y;           //私有数据
};

//成员函数的实现
Point::Point(Point &p){
	x=p.x;
	y=p.y;
	cout<<"Calling the copy constructor"<<endl;
}

//形参为Point类对象的函数
void fun1(Point p){
	cout<<p.getX()<<endl;
}

//返回值为Point类对象的函数
Point fun2(){
	Point a(1,2);
	return a;
}

//主程序
int main(){
	Point a(4,5);   //第一个对象a
	Point b=a;      //情况一,用a初始化b。第一次调用复制构造函数
	cout<<b.getX()<<endl;
	fun1(b);        //情况二,对象b作为fun1的实参。第二次调用复制构造函数
	b=fun2();       //情况三,函数的返回值是类对象,函数返回时,调用复制构造函数
	cout<<b.getX()<<endl;
	return 0;
}

在这里插入图片描述
析构函数:完成对对象被删除前的一些清理工作,对象消亡时自动调用释放资源,第六章

析构函数的原型 ~类名()
析构函数没有参数,没有返回类型

#include <iostream>
using namespace std;
class Point{
public:
	Point(int xx,int yy);
	~Point();
	//...其他函数原型
	private:
		int x,y;
};

Point::Point(int xx, int yy)
{
	x=xx;
	y=yy;
}
Point::~Point(){
}
//...其他函数的实现略

类的组合(类中的成员是另一个类的对象)

组合类的构造函数设计

原则:不仅要负责对本类中的基本类型成员数据初始化,也要对对象成员初始化
声明形式:

类名::类名(对象成员所需的形参,本类成员形参):
	对象1(参数),对象2(参数),......
{
//函数体其他语句
}

成员对象构造函数,按对象成员的定义顺序,先声明者先构造。
初始化列表中未出现的成员对象,调用默认构造函数初始化

例4-4 线段类

使用一个类来描述线段,使用4.3节中的Point类的对象来表示端点。这个问题可以用类的组合来解决,使Line类包括Point类的两个对象p1和p2,作为其数据成员,Line类具有计算线段长度的功能,在构造函数中实现。

//4_4.cpp
#include <iostream>
#include <cmath>
using namespace std;
class Point{
public:
	Point(int xx=0, int yy=0){
		x=xx;
		y=yy;
	}
	Point(Point &p);
	int getX() {return x;}
	int getY() {return y;}
private:
	int x,y;
};

Point::Point(Point &p){
	x=p.x;
	y=p.y;
	cout<<"Calling the copy constructor of Point"<<endl;
}

//类的组合
class Line{
public:
	Line(Point xp1, Point xp2);
	Line(Line &1);
	double getLen() {return len;}
private:
	Point p1,p2;
	double len;
};

//组合类的构造函数
Line::Line(Point xp1, Point xp2):p1(xp1),p2(xp2){
	cout<<"Calling constructor of Line"<<endl;
	double x=static_cast<double>(p1.getX()-p2.getX());
	double y=static_cast<double>(p1.getY()-p2.getY());
	len=sqrt(x*x+y*y);
}

//组合类的复制构造函数
Line::Line(Line &1):p1(1.p1),p2(1.p2){
	cout<<"Calling the copy constructor of Line"<<endl;
	len=1.len;
}

//主函数
int main(){
	Pint myp1(1,1) , myp2(4,5);
	Line line(myp1,myp2);
	Line line2(line);
	cout<<"The length of the line is:";
	cout<<line.getLen()<<endl;
	cout<<"The length of the line2 is:";
	cout<<line2.getLen()<<endl;
	return 0;
}

前向引用声明
两个类相互引用

class B; //前向引用声明(只能使用被声明的符号,不能涉及类的任何细节)
class A{
public:
	void f(B b);
};
class B{
public:
	void g(A a);
};

UML简介

Things Relationships Diagrams
类图 数据成员 函数成员
对象图
依赖关系 源目标
关联关系 重数
包含关系 共享聚集(部分可以参加多个整体)、组合(整体与部分共存)
泛化关系 继承(子类继承父类)

结构体(一种特殊形态的类)

与类的唯一区别

类的缺省访问权限是private,结构体的缺省访问权限是public

struct 结构体名称{
	公有成员
protect:
	保护型成员
private:
	私有成员
};

如果:

一个结构体的全部数据成员都是公共成员
没有用户定义的构造函数
没有基类和虚函数(第七章)
这个结构体的变量可以用下面的语法形式初始化:

例4-7 用结构体表示学生的基本信息

#include <iostream>
#include <iomanip>
#include <string>
using namespace std;

struct Student{
		int num;   //学号
		string name;//姓名,字符串对象,第6章
		char sex; 
		int age;
};
int main(){
	Student stu = {97001, "Lin Lin ", 'F', 19};
	cout<<"Num: "<< stu.num <<endl;
	cout<<"Name: "<< stu.name <<endl;
	cout<<"Sex: "<< stu.sex <<endl;
	cout<<"Age: "<< stu.age <<endl;
	return 0;
}

联合体

union 联合体名称{
	公有成员
protected:
	保护型成员
private:
	私有成员
};

特点:

成员共用同一组内存单元
任何两个成员不会同时有效

union Mark{     //表示成绩的联合体
	char grade; //等级制的成绩
	bool pass;  //只记是否通过课程的成绩
	int percent;//百分制的成绩
};

无名联合体(只是规定要共用内存空间)

union{
	int i;
	float f;
}

例4-8 使用联合体保存成绩信息,并且输出。

#include <string>
#include <iostream>
using namespace std;
class ExamInfo{
private:
	string name; //课程名称
	enum { GRADE, PASS, PERCENTAGE } mode;//计分方式
	union{
		char grade;
		bool pass;
		int percent;
	};
public:
//三种构造函数,分别用等级、是否通过和百分初始化
	ExamInfo(string name, char grade)
		: name(name), mode(GRADE), grade(grade) { }
	ExamInfo(string name, bool pass)
		: name(name), mode(PASS), pass(pass) { }
	ExamInfo(string name, int percent)
		: name(name), mode(PERCENTAGE), percent(percent) { }
	void show();
void ExamInfo::show(){
	cout << name << ": ";
	switch (mode){
		case GRADE: cout<< grade; break;
		case PASS: cout<< (pass ? "PASS" : "FAIL"); break;
		case PERCENTAGE: cout << percent; break;
	}
	cout << endl;
}

int main(){
	ExamInfo course1("English", 'B');
	ExamInfo course2("Calculus", ture);
	ExamInfo course3("C++ Programming", 85);
	course1.show();
	course2.show();
	course3.show();
	return 0;
}
};

枚举类

语法形式
enum class 枚举类型名:底层类型{枚举值列表};
枚举类的优势

强作用域,其作用域限制在枚举类中
比如,使用Type的枚举值General Type::General
转换限制

#include <iostream>
using namespace std;
enum class Side{ Right, Left};
enum class Thing{ Wrong, Right};//不冲突
int main()
{
Side s = Side::Right;
Thing w = Thing::Wrong;
cout<<(s==w)<<endl; //编译错误,无法直接比较不同枚举类
return 0;
}

在这里插入图片描述

#include "stdafx.h"
#include <iostream>
using namespace std;

enum CPU_Rank{P1=1,P2,P3,P4,P5,P6,P7};
class CPU
{
private:
	CPU_Rank rank;
	int frequency;
	float voltage;
public:
	CPU(CPU_Rank r, int f, float v)
	{
		rank = r;
		frequency = f;
		voltage = v;
		cout<<"构造了一个CPU!"<<endl;
	}
	~CPU () {cout<<"析构了一个CPU!"<<endl;}
	//外部接口
	CPU_Rank GetRank() const{ return rank;}
	int GetFrequency() const{ return frequency;}
	float GetVoltage() const{ return voltage;}

	void SetRank(CPU_Rank r){rank = r;}
	void SetFrequency(int f){frequency = f;}
	void SetVoltage(float v){voltage = v;}	

	void Run(){cout<<"CPU开始运行!"<<endl;}
	void Stop(){cout<<"CPU停止运行!"<<endl;}
};

int main()
{
	CPU a(P6,300,2.8);
	a.Run();
	a.Stop();
	
return 0;
}

注意部件组装、构造与析构顺序
在这里插入图片描述

enum RAM_Type{DDR2=2,DDR3,DDR4};
class RAM
{
private:
	enum RAM_Type type;
	unsigned int frequency;//MHz
	unsigned int size;//GB
	
public:
	RAM(RAM_Type t, unsigned int f, unsigned int s)
	{
	type = t;
	frequency = f;
	
	}
	
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值