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

目录

第8章 类和对象

面向对象方法概述

类的声明和对象的定义

对象成员的引用

类的封装性和信息隐蔽

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

构造函数

析构函数

对象数组

对象指针

共用数据的保护

扫描二维码关注公众号,回复: 12873309 查看本文章

对象的动态建立和释放

对象的赋值和复制

静态成员

友元

类模板

第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