C++程序设计【谭浩强】第三篇:基于对象的程序设计

目录

第8章 类和对象

面向对象方法概述

类的声明和对象的定义

对象成员的引用

类的封装性和信息隐蔽

第9章 关于类和对象的进一步讨论

构造函数

析构函数

对象数组

对象指针

共用数据的保护

对象的动态建立和释放

对象的赋值和复制

静态成员

友元

类模板

第10章 运算符重载

什么是运算重载符

运算符重载的方法和规则

运算符重载函数作为类成员函数和友元函数

重载双目运算符

重载单目运算符

重载流插入运算符和流提取运算符

不同类型数据间转换

用类型转换函数进行类型转换


第8章 类和对象

面向对象方法概述

面向过程:适用于规模比较小的程序,其实是面向一个个函数实现一个个功能进行的,程序 = 算法 + 数据结构

面向对象:适用于规模比较大的程序,面向数据和函数封装成的对象,程序 = 多个对象 + 消息【对象 = 算法 + 数据结构】

对象:客观世界中的任何一个具体的事物都可以看做具体的对象,在C++中,对象由数据函数组成

属性:对象的静态特征,例如班级的学生人数、所在教室

行为:对象的动态特征,例如班级开会等,行为由消息控制

封装:一是将数据和代码封装在一个对象中,二是将对象中某些部分对外隐蔽

抽象:类是对象的抽象,类是对象的模板,对象是类的特例,或者说对象是类的具体表现形式

继承与重用:继承就是能够利用之前的类再扩充一些功能生成一个新类,重用是软件重用

多态:给不同的对象发同一个消息,他们分别执行不同的动作叫多态

类的声明和对象的定义

类是抽象的,不占用内存,而对象是具体的,占用内存,其实类就是一种广义上的数据结构

类的声明方法也是由结构体类型发展而来的,在C++中,二者甚至可以通用,区别在于未指定时类会默认private,而结构体会默认public,不过尽量采用class来建立类,private和public是成员访问限定符

类把数据和操作封装在一起了,一般来说类把数据隐藏起来,而把成员函数作为对外的接口

使用类函数注意事项:注意调用权限、注意函数的作用域(它能调用什么范围的数据和函数)

public内的成员函数是类的对外接口,private内的成员函数是类中其它成员的工具函数,类外的用户不能够调用

在类外也可以定义成员函数,举例如下:

class Student
{
    public:
        void display();
    private:
        int num;
        string name;
        char sex;
};

void Student::display()
{
    cout<<num<<endl;
    cout<<name<<endl;
    cout<<sex<<endl;
}

Student stu1, stu2;

注意上面的成员函数是怎么定义的 —— void Student::display() ,其中那两个冒号::代表这个函数属于这两个冒号前的那个类的类内成员,如果只有这两个冒号,或者什么都没有,那么说明这个函数不是成员函数,而是全局函数

一个对象所占用的空间只与该对象中的数据成员所占用的空间有关,而与成员函数无关,也就是说省了存类内函数的空间

对象成员的引用

类内成员的三种引用方式

(1)对象名.成员名

stu.num

(2)利用指针:

pStu->num     //方式一
(*pStu).num   //方式二

(3)利用引用:stu2是stu1的别名,它俩指的是同一块内存

Student stu1;
Studnet &stu2 = stu1;

对于C++来说,只要把类定义好,编写程序的工作就十分十分的简单了

类的封装性和信息隐蔽

类的作用就是把数据算法封装在用户声明的抽象数据类型之中,用户主要通过调用公用的成员函数来实现类提供的功能(例如对数据成员赋值、显示数据成员的值、对数据进行加工等)

公用接口与私有实现的分离:例如在软件开发过程中,必须要实现两者的分离,这样的话只要类的接口没有改变,那么对私有实现的改变不会影响到程序的其它部分

如果一个类知识被一个程序使用,那么类的声明和成员函数的定义可以直接写在程序的开头,但是如果这个类被多个程序使用,那么这样的重复工作的量就太大了。一般在面向对象开发的时候,通用做法是把类的声明(含成员函数的声明)放在头文件里面,如果用户想要用这个类,那么就把这个头文件包进来就好啦。同时呢,为了信息隐蔽,对类成员函数一般不放在头文件中,而是另外放在一个问价当中。

类声明和成员函数定义的分离举例【共三个文件】:

文件一:头文件内进行类的声明:

//文件名:student.h
//这是个类声明头文件
#pragma once          
#include <string>
using namespace std;

class Student          //类声明
{
public:
	void display();   //公用成员函数声明
private:
	int num;
	string name;
	char sex;
};

文件二:类成员函数的定义

//文件名:student.cpp
#include <iostream>
#include "student.h"         //注意包含这个类声明头文件
using namespace std;
 //在本文件中进行函数的定义
void Student::display()      //注意这里的两个冒号很重要
{
	cout << num << endl;
	cout << name << endl;
	cout << sex << endl;
}

文件三:主函数

//文件名:main.cpp
#include <iostream>
#include "student.h"    //包含这个类声明头文件
using namespace std;

int main()
{
	Student stu;        //定义一个对象
	stu.display();      //执行对象的display函数,这里你点那个点就会发现其它的成员都访问不了
	return 0;
}

对象是谁?stu

方法是谁?display()

消息是谁?stu.display()

 

第9章 关于类和对象的进一步讨论

构造函数

简单来说,构造函数就是处理对象的初始化。需要注意的是类的数据成员是不能在声明类的时候初始化的,因为类只是一种数据类型,而不是真正的对象。

构造函数举例:

#include <iostream>
using namespace std;
class Time
{
public:
	Time()  //定义构造成员函数,函数名与类名相同,通过构造函数对对象中的数据成员赋初值
	{
		hour = 0;
		minute = 0;
		sec = 0;
	}
	void set_time();
	void show_time();
private:
	int hour;
	int minute;
	int sec;
};

//定义成员函数用于赋值
void Time::set_time()
{
	cin >> hour;
	cin >> minute;
	cin >> sec;
}

//定义成员函数用于输出
void Time::show_time()
{
	cout << hour << ':' << minute << ':' << sec;
}

//主函数
int main()
{
	Time t;        //建立对象t,同时调用构造函数t.Time()进行对象初始化
	//t.set_time();
	t.show_time();
	return 0;
}

除此之外可以采用参数初始化表进行数据成员的初始化

构造函数重载:在一个类中可以定义多个构造函数,以便对类对象提供不同的初始化选择,这些构造函数具有相同的名字,但是参数的个数或者参数的类型不相同,这就称为构造函数的重载,但是一个类只有一个默认构造函数

析构函数

析构函数前面有一个 ~ 符号,其作用与构造函数相反,析构函数的作用并不是删除对象,而是在撤销对象占用内存之前完成一些清理工作。一个类可以有很多的构造函数(重载),但是只有一个析构函数。先构造的后析构,后构造的先析构,类似于一个栈

对象数组

数组不仅仅可以由简单变量组成,也可以由对象组成

对象指针

对象所占用的空间的首地址就是对象的指针

(1)指向对象中数据成员的指针

定义方法与结构体一样

(2)指向对象中函数成员的指针

普通函数的指针变量:void (* p) ( );      这里p是指向void类型函数的指针变量

指向对象成员函数的指针变量:void (Time:: * p)( );     这里p是指向Time类中公用成员函数的指针变量

怎样定义呢?举例:p = &Time::get_time;  注意这里的get_time只是函数名,没有括号哦

共用数据的保护

保证数据能够在一定范围内共享,又要保证它不被任意修改,这时可以使用const把有关数据定义为常量

对象的动态建立和释放

动态建立和释放对象的举例:【类似于 malloc() 和 free() 】

Box * pt;      //定义一个 Box * 类型的指针变量 pt
pt = new Box;  //在 pt 中存放新建的对象的首地址
delete pt;     //释放 pt 所指向的内存空间

对象的赋值和复制

复制 = 新建 + 赋值

静态成员

静态数据成员

如果希望各个对象中的某个数据成员都是一致的,那么在类中可以这样定义:

static int height;

静态成员函数

与静态数据成员相类似

static float sum();

友元

友元就是介于公用和私有之间的一种东西。假如有个函数定义在了本类外(可以是非成员函数,也可以是其它类的成员函数)那么在类体中用 friend 对这个函数进行声明,这个函数就称为本类的友元函数,这个友元函数可以访问这个类的私有成员。

举例:

#include <iostream>
using namespace std;
class Time
{
public:
	Time(int,int,int);
	friend void display(Time &);   //声明display为Time类的友元函数
private:
	int hour;
	int minute;
	int sec;
};

//定义构造函数用于赋初值
Time::Time(int h,int m,int s)
{
	hour = h;
	minute = m;
	sec = s;
}

//定义成员函数用于输出
void display(Time & t)  //t是Time类对象的引用,这个函数是友元函数
{
	cout << t.hour << ':' << t.minute << ':' << t.sec;
}

//主函数
int main()
{
	Time t(10,13,20);  
	display(t);   //t是Time类对象
	return 0;
}

类模板

类模板使用举例:

#include <iostream>
using namespace std;
template <class numtype>
class Compare
{
public:
	Compare(numtype a, numtype b)
	{
		x = a;
		y = b;
	}
	numtype max()
	{
		return(x > y) ? x : y;
	}
	numtype min()
	{
		return(x < y) ? x : y;
	}
private:
	numtype x, y;
};

int main()
{
	Compare <int> cmp_1(3, 7);
	cout << cmp_1.max() << " is the max of two numbers" << endl;
	Compare <float> cmp_2(45.6, 98.7);
	cout << cmp_2.min() << " is the min of two numbers" << endl;
	return 0;
}

 

第10章 运算符重载

什么是运算重载符

所谓的重载,就是重新赋予新的含义。函数重载就是一名多用,同一个函数名可以用来代表不同功能的函数;运算符重载我们其实也是一直在用(例如我们用+进行整数、浮点数等等的运算,其实这个就是运算符重载)

所谓的运算符重载就是赋予运算符新的意义

运算符重载的方法和规则

运算符重载函数作为类成员函数和友元函数

重载双目运算符

重载单目运算符

重载流插入运算符和流提取运算符

不同类型数据间转换

用类型转换函数进行类型转换

猜你喜欢

转载自blog.csdn.net/weixin_43450646/article/details/106996297