用类比法对C++中类和对象的深入剖析

2018-01-06 00:57徐晓蓉李永军
电脑知识与技术 2017年35期
关键词:方法

徐晓蓉+李永军

摘要:类和对象是面向对象程序设计中非常重要的概念,也是初学者不容易理解的概念之一,该文用类比的方法清楚地解释了类和对象的概念,并在内存层面对类和对象进行了深入的剖析,使学生能更加清晰地理解什么是类,什么是对象,以及类和对象在内存中的存储形式。

关键词:类和对象;数据和操作;方法;属性和行为

中图分类号:TP312 文献标识码:A 文章编号:1009-3044(2017)35-0106-03

A Thorough Analysis of Class and Object in C ++ by Analogy

XU Xiao-rong1, LI Yong-jun2

(1.College of Computer Science and Technology, Hunan University of Arts and Science, Changde 415000, China;2.School of Physics and Electronics, Henan University, Kaifeng 475004, China)

Abstract: Class and object are very important concepts in the Object-Oriented Programming, and they are very difficult to be understood by the beginners. In this paper, the concepts of class and object are explained clearly by analogy, and class and object are analyzed in memory, so that students can more easily understand what the class is , what the object is, and how class and object are stored in memory.

Key words:classes and objects; data and operation;methods; properties and behaviors

1 背景

類和对象是C++等面向对象程序设计中最重要的两个基本概念,但就作者多年教授这门课的经验看,学生大多因为有面向过程程序设计的基础,最初都很难清楚地理解面向对象程序设计中的类和对象这两个概念,从而碰到问题总是很容易想到面向过程而很难想到使用面向对象的方法来解决问题。本文通过类比法,对类和对象的定义进行了对比、分析和解释,并在内存层面深入剖析了类和对象在内存中的存在形式,有助于初学者更快、更准确的理解类和对象的概念。

2 用类比法理解类和对象的定义

2.1 类的定义

数学上,所谓定义,即是对于一种事物的本质特征的确切而简要的说明;比如,质数的定义:除了1和它本身以外不再有其他因数的大于1的自然数。

而在C++中,类的定义也是先找出类的特征,再给出类定义的描述,即必须首先对某类的若干对象进行分析,总结出该类对象(所关注)静态的属性(或数据)和动态的方法(或行为、或操作),即特征,最后再使用关键词class将所有属性和方法整合起来来形成类的定义。

比如:通过对很多个人特征的分析发现,对于人,通常关注的是姓名,性别,年龄等这些静态的属性,除此之外,人还有一些动态的行为,比如会思考、会说话、会微笑等等。当总结出了人的静态和动态的特征之后,就可以定义什么是人!用 c++语言来描述出来就是如下程序段:

[例程1]

class Person

{private:

char name[20];

int age;

char sex;

public:

void think()

{ cout << "I am a person, and I can think!"<

}

void talk()

{ cout << "I am a person, and I can talk with you!" << endl;

}

void smile()

{ cout << "I am a person, and I like smiling!" << endl;

}

};

[例程1]中,class是C++中用来定义类的关键词,而Person是定义的类的名字,类名可以由程序员自己定义。从[例程1]中可以看出,C++中动态行为是用函数来表达的,称为成员函数,每一个成员函数都可以作为人与外界沟通交流的一个接口,所以,一般将成员函数定义成公有的(即public:)。而静态的属性,称为数据成员,是用类型及属性名来表示,一般是每个人所特有的,因此,一般将其定义为私有的(即private:)。当然,每个类中有几个成员函数以及它们的类型、参数及具体实现的功能需要程序员自己去按实际需要来定义与实现,数据成员有几个以及其名字、类型也是如此。

2.2 对象的定义

定义了类,相当于定义了一种新的数据类型,与系统的基本数据类型相似。也就是说,在[例程1]中定义Person类之后,就可以像以前使用的int、double、float等一样来使用Person了,只不过,用系统的基本数据类型定义的变量,通常称为变量,而用用户自己定义的类型如Person定义的变量,通常称之为对象而已,如:

int a; //a是变量,a中可以存放一个int型的数据。

Person p; //而p,则是对象,p中可以存放一个Person型的数据。

对象的定义格式为:类型 对象名;

2.3 类和对象的使用

类是抽象的,而对象则是具体的。类和对象的关系就好比人和某人张三的关系,人只是存在于我们的意念中,而张三这个人却是实实在在存在与这个现实世界中的。张三具有人的所有属性和行为。[例程1]中的Person类就是抽象的,要想使用Person类,必須定义Person类的对象,通过具体对象来使用类。如Person p; 定义了具体对象之后,就可以通过给对象发送指令来使用类,如p.smile();等。

3 类和对象的内存

3.1 类的内存

类是抽象的,因此,类的定义只是一种定义性说明,类定义中的数据成员本身是不占内存空间的,也就是说,类的内存空间仅仅是定义类的那段代码所占据的内存空间。

3.2 对象的内存

对象是具体的,具有类的所有属性和行为。所以,理论上来说,对对象而言,它的属性和行为都要占据内存空间。

1) 普通类对象的内存

定义Person类对象,Person p1,p2;那么,p1和p2对象的内存示意图如下图1,图2:

很显然,对于同一个类的对象,每个对象中都有相同的成员函数,这将造成内存资源的极大浪费,因此,系统是将这些成员函数专门存储在一个地方,每个对象的内存中只存储相应的属性,p1、p2的内存状态如图3所示。从图3中可以看出,每个对象在内存中存储的时候,只存储属于对象自己的数据成员,而没有成员函数。对于不同对象如何使用存储在同一个地方的相同成员函数在介绍this指针时再做解释。

2) 派生类对象的内存

[例程2]在上面[例程1]的Person类的基础上派生出如下的Student类。

class Student :public Person

{

int num;

char major[30];

public:

void printMessage()

{cout <<"num:"<

}};

从理论上讲,派生类具有基类的所有属性和行为。如果有Student s; s对象的内存状态如图4所示。由图4可知,派生类对象的属性具有两类:基类的所有属性、自己新增的属性。但需注意,基类的属性在派生类中是以无名对象(内嵌对象用椭圆表示,以下类同。)的形式存在的, 所以,s对象的内存示意如图5所示。

3) 含虚基类的派生类对象的内存

当派生类的两个基类有共同基类时,在派生类对象中就会有两个共同基类的对象,如[例程3]中的Derive类的对象。

[例程3]

class Base

{

int b;

public:

Base(int x=0)

{ b=x;

cout<<"&b="<<&b<

}

};

class Base1: public Base

{

int b1;

public:

Base1(int x=0,int y=0):Base(x)

{ b1=y; }

};

class Base2: public Base

{

int b2;

public:

Base2(int x=0,int y=0):Base(x)

{ b2=y; }

};

class Derive:public Base1,public Base2

{

int c;

public:

Derive(int x,int y,int z): Base1(100,y),Base2(200,z)

{ c=z; }

};

void main()

{

Derive d(3,2,1); }

这时,在主函数中用Derive d(3,2,1)定义d对象之后,d的内存状态如图6所示。很显然,对象d中有两个共同基类Base类的对象,这样,会造成二义性。由于在Base类的构造函数中加入了输出b成员的地址,通过执行程序,由图7可以很明显的看到,输出了两次b的地址,说明,在d对象中,有两个不同的Base类的对象。

为了消除这种二义性,c++中引入了虚基类,如[例程4]所示。

[例程4]该程序是在[例程3]的基础上仅仅加了2个virtual和一个Base(300)

class Base

{

int b;

public:

Base(int x=0)

{ b=x;

cout<<"&b="<<&b<

}

};

class Base1: virtual public Base

{

int b1;

public:

Base1(int x=0,int y=0):Base(x)

{ b1=y; }

};

class Base2: virtual public Base

{

int b2;

public:

Base2(int x=0,int y=0):Base(x)

{ b2=y; }

};

class Derive:public Base1,public Base2

{

int c;

public:

Derive(int x,int y,int z): Base(300),Base1(100,y),Base2(200,z)

{ c=z; }

};

void main()

{

Derive d(3,2,1);

}

d對象的内存状态如图9所示,虽然,从内存看好似还是有两个共同基类Base类的对象,但此时,这两个对象的b的值已经是相同的,且是派生类Derive的构造函数提供的值,而且程序执行结果只输出一个b的地址,如图10所示。这说明,此时,在d对象中,已经只有一个共同基类Base类的对象了,从而消除了二义性,由此,我们也可以得到d对象的内存示意图,如图11所示。

4 结束语

初学者往往对类和对象的概念理解起来很不容易,本文通过类比法对类和对象的概念进行了分析解释,并从内存层面对类和对象进行了深入的剖析,让学生可以从概念到本质更好的理解类和对象的概念,通过实际教学和对学生的调查表明,通过此学习,学生确实可以更深一层的理解类和对象的概念。

参考文献:

[1] 洪阳. C++中学习类的设计方法和途径的探究[J]. 宝钢科技, 2014,40(1):60-63.

[2] 陈维兴, 林小茶. C++面向对象程序设计教程[M].北京: 清华大学出版社, 2009.

[3] 谭浩强. C++程序设计[M]. 3版.北京: 清华大学出版社, 2015.

[4] 本贾尼·斯特劳斯特鲁普. C++程序设计:原理与实践(基础篇)[M]. 2版.北京: 机械工业出版社, 2017.

猜你喜欢
方法
中医特有的急救方法
高中数学教学改革的方法
化学反应多变幻 “虚拟”方法帮大忙
变快的方法
学习方法
可能是方法不对
用对方法才能瘦
四大方法 教你不再“坐以待病”!
赚钱方法
捕鱼