进入面向对象的程序设计了
会写得仔细一点
类和对象的定义(类是同一类对象的抽象)
定义类
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;
}