c++基础第二章(对象)

前言,c++是面对对象的语言

任何一个对象都应当具有 属性 和 行为 这两个要素。一个对象一般是由一组属性和一组行为构成的。

也就是说 在 c++ 中对象是由  数据(属性)  和 函数(行为) 两部分组成。函数是用来对数据进行操作,用来实现某种功能。

对象具有封装性 和信息隐蔽性可以对一个对象进行封装处理,把它的一部分属性和功能对外界进行屏蔽,也就是说从外界看不到,甚至不可知

  (1).例如  DVD 机里有电路板和各种机械控制部件,但是外部是看不到的,我们只能从外面看到他只是一个“黑箱子”,表面有几个按钮,这就是DVD机对外界的接口,人们不逼你了解DVD机里面的结构和工作原理,只需要直到按某一个键就能使DVD机执行相应的操作.

  优点:大大降低了人们操作对对象的复杂程度,使用对象的人完全不必知道对象内部的具体细节,只需要了解外部功能就可以了,就像傻瓜相机,你不必知道它是怎么做到的,你只需要像傻瓜一样会按按钮就可以了。官方的说就是把对象的内部实现和外部行为分隔开来。

封装性

(1)将有关数据和操作代码封装在一个对象中,形成一个基本单位,各个对象互不干扰。

(2)将对象中某些部分对外部隐藏(隐藏内部细节),只留下少数接口(不然怎么和外部联系,外部怎么使用这个对象呢?),这样做有利于信息安全,防止无关的人了解和修改数据。

引出类

抽象:作用是表示同一类事物的本质。例如所有国籍为中国的人,可以抽象为“中国人”,凡是有轮子,能滚动前进的陆地交通工具,抽象为“车”。

而对象是具体存在的,例如一个三角形可以作为一个对象,10个尺寸不同的三角形是10个对象,这10个对象有相同的属性和行为(因为他们只是具体的边长不同而已),这时可以将这10个对象归为一类。正如  10个中国人属于“中国人”类。

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

一.1,类的声明

class Student
{
	private:		//私有数据和成员函数 
	 int ID;
	 string name;
	 string sex; 
	public:			//公用的数据和成员函数 
	void display()
	{
		cout << "ID = " << ID << endl;
		cout << "name = " << name << endl;
		cout << "sex = " << sex << endl;
	}
} ;
Student stud1, stud2; //定义了Student 类的对象stud1和stud2 

在类内的定义中即不指定private,也不指定public,则系统默认为是私有的。

类的一般形式

class 类名 
{
	private:		
            //私有数据和成员函数 
	public:			 
	    //公用的数据和成员函数
} ;

private :被声明为私有成员,只能被本类中的成员函数引用,类外不能调用(友元函数除外,第三章会讲)

public :被声明为公用的,既可以被本类的成员函数引用,还可以外界调用。

举个栗子,这个类就相当与你的家,私有private就是卧室,public就是客厅,而卧室只允许自己的家人进,不允许外人进的。而客厅嘛就可以招待各种客人了。

在一个类中  private 和 public可以出现多次,但是为了使程序清晰:使每一个成员访问限定符在类的定义体中只出现一次。

一.2,类的成员函数

简称类函数,用法与函数一样,但是在因为类中:他是一个类的一个成员,所以他可以被指定为 private(私有的)  public(共有的)  protected(受保护的).

使用时要注意权限(是否能被调用)以及它的作用域(函数能使用什么范围内中的数据和函数)例如私有成员函数只能被本类中的其他成员函数所调用,不能被类外调用,成员函数可以访问本类中任何成员,可以引用在本作用域中有效的数据。

一般做法是将需要被外界调用的成员函数指定为public,他们是类对外的接口

但是有些函数并不是准备为外界调用的,你不想外界使用,只是能让本类函数用,那就指定为private

在类外定义成员函数

#include<iostream>
using namespace std;

class Student 
{
	public:			//公用的数据和成员函数 
		void display()
	private:		//私有数据和成员函数 
		int ID;
	 	string name;
	 	string sex; 
} ;

void Student::display() 
{
	cout << "ID = " << ID << endl;
	cout << "name = " << name << endl;
	cout << "sex = " << sex << endl;
}

在 类内定义成员函数是不需要在函数名字前面加上类名,因为你在类内定义,这个函数就属于这个类,但是为了整洁,我们一般把函数写在外面。但是成员函数写在外面就必须加上类名了,不然不知道这个函数是哪个类的成员函数

一般我们在类内声明函数,在类外定义函数,这样可以减少类的长度,使类体更清晰,便于阅读,而且可以使类的接口和类的实现细节分开。从用户角度看这个类就像一个黑匣子,看不到细节,只知道怎么用。

内置成员函数。

字面意思  就是说  成员函数也可以内置  在类外写成员函数时前面加上  inline 就可以了。(很鸡助 没什么卵用,建议不要用,这种方法还必须把声明成员函数 和定义成员函数写到一个文件内,不然编译不过)

成员函数的的储存方式。

用类定义对象时,系统会为每个对象分配储存空间, 如果一个类包括了数据和函数,按理说是要分别为数据和函数代码分配储存空间的,那一个类定义10个对象是否需要为每一个对象的数据和函数代码分配空间,并把他们封装在一起呢?

事实并不是这样的:同一类的不同对象中的数据成员的值一般是不相同的,而不同对象的函数的代码是相同的,不论调用哪一个对象的函数的代码,其实调用的都是相同的内容的代码。

显然这样做会节约大量空间。c++ 编译系统也就是这样做的,因此对于每个对象所占用的储存空间只是该对象的数据成员所占用的储存空间,而不包括函数代码所占用的储存空间。

#include<iostream>
using namespace std;
class Time
{
	public:
		int hour;
		int minute;
		int second;
		void set()
		{
			char a , b, c;
			cin >> a >> b >> c;
		}
}; 
int main ()
{
	Time time1;
	cout << sizeof(time1) << endl;
	return 0;
}

sizeof(Time)的答案是  12   3个int型  一个int 4个字节 ,set()函数内的3个定义并没有算在  Time 定义对象的空间内

虽然成员函数并没有放在对象的储存空间中,但是从逻辑角度成员函数是和数据一起封装在一个对象中的,只允许本对象中的函数访问同一对象中的私有数据。

一.3,对象成员的引用

(1)通过对象名和成员运算符访问对象中的成员

stud1.num = 100;    //假设num已经定义为公用的整型数据成员 
num = 100;    //没有指出是哪个对象

访问的一般形式为

对象名.成员名

stud1.display();    //正确,调用stu1的公用成员函数
display();         //没有指明哪个对象的display();这时这个就是个函数不是成员函数。

所以 在 类中至少有一个公用成员函数,作为对外的接口,否则就无法对对象进行任何操作

通过指向对象的指针访问对象中的成员

#include<iostream>
using namespace std;
class Time
{
	public:		        //数据成员是公用的才能在外部访问 
		int hour;
		int minute;
		int second;
}; 

int main ()
{
	Time t, *p;		//定义对象t和指针变量p 
	p = &t; 		//使p指向对象t 
	cout << p->hour;	//输出p指向的对象中的成员hour 
	return 0;
}

通过对象引用访问对象中的成员

Time t1;        
Time &t2 = t1;
cout << t2.hour;     //hour是public内的

写个例题

找出一个整型数组中的元素的最大值

#include<iostream>
using namespace std;
class Array_max
{
	public:
		void set_value();
		void max_value();
		void show_value();
	private:		        
		int array[10];
		int max;
}; 

void Array_max::set_value()
{
	int i;
	for(int i = 0; i < 10; i++)
	cin >> array[i]	;
	
}
void Array_max::max_value()
{
	int i ;
	max = array[0];
	for(int i = 1; i < 10; i++)
	if(max < array[i])
	max = array[i];
}
void Array_max::show_value()
{
	cout << "max = " << max << endl;
}
int main ()
{
	Array_max arrmax;
	arrmax.set_value();
	arrmax.max_value();
	arrmax.show_value();
	return 0;
}

下面长篇文章来袭

虽然很长 但是读过之后对类还有成员函数的封装  信息的隐藏会有更深的理解

类的封装性和信息隐藏

公用接口与私有实现的分离

一般把所有的数据指定为私有,使他们与外界分离,把需要让外界调用的成员函数指定为公用的。在类外虽然不能直接访问私有数据成员,但是可以通过调用公有成员函数来引用甚至修改私有数据成员。因此外界与对象的唯一联系渠道就是调用公有成员函数,这样可以使类Yui外界的联系降到最低。可以说公有成员函数是用户使用类的公用接口,就是类的对外接口

就像照相机,人只需要知道按什么按键能实现什么功能就可以了,其中的原理不必了解那是设计师和厂家的事情。快门就是一个公用接口,用户可以通过快门照相,但不能改变相机的结构和功能。一切与用户无关的操作细节都被封装在了相机内,用户看不见,摸不到,改不了。这样就实现了接口与现实分离

通过成员函数对数据成员进行操作称为类的实的功能实现。为了防止用户任意更改公用成员函数,改变对数据进行的操作,往往不让用户看到公用成员函数的源代码,显然更不能修改,用户只能接触到公用成员函数的目标代码。可以看到类中被操作的数据是私有的,类的功能的实现细节对用户是隐蔽的,这种实现成为私有实现。这种“类的公用接口与私有实现的分离”形成了信息的隐蔽。

用户接触到是公用的接口,而不能接触到被隐蔽的数据和实现的具体细节。也就是说你只知道这个函数能实现什么功能,而怎么实现的并不知道。

类的声明和成员函数定义的分离

一个类如果只被一个程序使用则只需要把这个类写到这个程序的开始就可以了

但是如果是一个类被多个程序使用,这样做的重复工作量就更大了,效率太低,这时就出现了把类的声明(包含成员函数的声明)放在指定的头文件中,如果想用这个类,只需要把有关的头文件包含进来即可,不必在程序中重复书写。提高编程效率

为了实现信息隐蔽,不让用户看到函数的执行细节,对类成员函数的定义一般不和类的声明一起放在头文件中,而放在另一个文件中。包含成员函数定义的文件就是类的实现(即通过调用成员函数用来实现类的功能)。特别注意:在系统提供的头文件中只包括对成员函数的声明,而不包括成员函数的定义。类声明和函数的定义分别放在两个文件中。

实际上就是 (1)类声明的头文件(后缀为.h或无后缀)(2)类实现文件(后缀为.cpp)包含类成员函数的定义;(3)类的使用的文件(后缀为.cpp)主文件

例子

文件1

//student.h

#include<string>
using namespace std;
class Student
{
	public :
		void display();
	private :
		int num;
		string name;
		string sex;
}

文件2

//student.cpp

#include<string>
#include<iostream>
#include"student.h"
using namespace std;
void Student::display()
{
	cout << "number =" << number << endl;
	cout << "name = " << name << endl;
	cout << "sex = " << sex << endl;
}

文件3

//main.cpp

#include<string>
#include<iostream>
#include"student.h"
using namespace std;
int main ()
{
	Student stud1;
	stud1.display();
	return 0;
}

注意,由于头文件student.h放在用户当前目录中,所以用   "student.h" 而不用 <student.h>

读者可能会思考这样一个问题,如果一个类声明多次被不同的程序所选用,每次都要对包含成员函数定义的源文件(例如上面的student.cpp)进行编译,这是否可以改进呢?现实是可以的,的确不需要每次对它进行重复编译,而只需要编译一次就可以了。把student.cpp第一次编译后所形成的目标文件保存起来,以后在需要时把它调出来直接与主文件的目标文件链接即可,这和使用库函数类似。

这也是成员函数的定义不放在一个头文件的一个好处,如果对成员函数的定义也放在类的声明的头文件中,那么不仅不能实现信息的隐藏,而且在对使用这些类的每一个程序的每一次编译时都要对成员函数进行编译,即同一个成员函数的定义会多次被重复编译。把成员函数的定义单独放在另一个文件中,单独编译,就可以做到不重复编译。

在实际工作中,我们并不是把一个类的声明做一个头文件,而是将若干个常用的功能相近的类的声明集中在一起,形成类库。

类库有两种:(1)c++编译系统提供的标志类库 (2)用户根据自己的需要做的用户类库,提供给自己或授权他人使用,称为自定义类库。

类库包括两部分:(1)类声明头文件;(2)已经过编译的成员函数的定义,它是目标文件。

用户只需要把类库装到自己的计算机系统中,并在程序中用到#incldue指令将有关的类的声明的头文件包含到程序中,就可以在程序中使用这些类

类声明头文件就成为用户使用类库的有效方法和公用接口。

这就实现接口与现实的分离,为软件开发商向用户提供类库创造了很好的条件,开发商把用户所需要的各种类的声明按类放在不同的头文件中,同时对包含成员函数定义的源文件进行编译,得到成员函数定义的目标代码。软件开发商只需要向用户提供这些头文件和类的实现的目标代码(不需要提供函数定义的源代码).用户使用库类中的类时,也只需要将有关头文件包含到自己的程序中,并在编译后链接成员函数定义的目标代码即可。用户可以看到头文件中类的声明和成员函数的原型声明,但是看不到定义成员函数的源代码,更无法修改成员函数的定义,开发商的权益就时得到了保护。

猜你喜欢

转载自blog.csdn.net/Harington/article/details/84166390