C++类和对象

类是面向对象程序设计方法的核心,利用类可以实现对数据的封装和隐蔽。

在面向过程的结构化程序设计中,程序的模块是由函数构成的,函数将逻辑上相关的语句和数据封装,用于完成特定的功能。

在面向对象程序设计中,程序模块是由类构成的。类是对逻辑上相关的函数与数据的封装,它是对问题的抽象描述。因此,后者的集成程度更高,也就更适合用于大型复杂程序的开发。

从另一个角度来理解类,首先回顾一下基本数据类型,比如int,double,bool等。当定义一个基本类型的变量时,究竟定义了什么呢?请看下面的语句:

int i;

bool b;

显然定义变量i是用于存储int型数据的,变量b是用来存放bool型数据的。但是变量声明的意义不只是这个,另一个同样重要的意义常被我们忽略了,这就是限定对变量的操作。例如对i可以进行算术运算、比较运算,对b可以进行逻辑运算、比较运算。这说明每一种数据类型都包括了数据本身的属性以及对数据的操作。

无论哪一种程序语言,其基本数据类型都是有限的,C++的基本数据类型也远不能满足描述现实世界中各种对象的需要。于是C++的语法提供了对自定义类型的支持,这就是类。类实际上相当于一种用户自定义的类型。

当定义了一个类之后,便可以定义该类的变量,这个变量就称为类的对象(或实例),这个定义的过程也称为类的实例化。

1.类的定义

以时钟为例,时钟类的定义如下:

class Clock

{

      public:

             void setTime(int newH,int newM,int newS);

             void showTime();

      private:

              int hour,minute,second; 

};

这里封装了时钟的数据和行为,分别称为Clock类的数据成员和函数成员。定义类的语法形式如下:

class 类名称

{

      public:

               外部接口

      protected:

              保护型成员

      private:

              私有成员

};

其中,public,protected,private分别表示对成员的不同访问权限控制。

注意,在类中可以只声明函数的原型,函数的实现(即函数体)可以在类外定义。

2.类成员的访问控制

类的成员包括数据成员和函数成员,分别描述问题的属性和行为,是不可分割的两个方面。

对类成员访问权限的控制,是通过设置成员的访问控制属性而实现的。访问控制属性可以有以下三种:公有类型(public)、私有类型(private)和保护类型(protected)。

公有类型成员定义了类的外部接口。公有成员用public关键字声明,在类外只能访问类的公有成员。对于时钟类,从外部只能调用setTime()和showTime()这两个公有类型的函数成员来改变或者查看时间。

在关键字private后面声明的就是类的私有成员,如果私有成员紧接着类名称,则关键字private可以省略。私有成员只能被本类的成员函数访问,来自类外部的任何访问都是非法的。这样,私有成员就完全隐蔽在类中,保护了数据的安全性。时钟类中的hour,minute,second都是私有成员。 

习惯 一般情况下,一个类的数据成员都应该声明为私有成员,这样,内部数据结构就不会对该类以外的其余部分造成影响,程序模块之间的相互作用就被降低到最小。

保护类型成员的性质和私有成员的性质类似,其差别在于继承过程中对产生的新类影响不同。

将需要隐蔽的成员,设为私有类型,成为一个外部无法访问的黑盒子;将提供给外界的接口,设为公有类型,对外部就是透明的;而保护成员,就相当于一个笼子,它给派生类提供一些特殊的访问属性。

设计一个类,是为了用它,要能够使用,就一定要设计必要的外部接口。

在类的定义中,具有不同访问属性的成员,可以按任意顺序出现。修饰访问属性的关键字也可以多次出现。但是一个成员只能具有一种访问属性。例如,将时钟类写成以下形式也是正确的:

class Clock

{

      public:

             void setTime(int newH,int newM,int newS);

      private:

             int hour,minute,second;

      public:

             void showTime();

};

习惯  在书写时习惯将公有类型放在最前面,这样便于阅读,因为它们是外部访问时所要了解的

3.对象

类实际上一种抽象机制,它描述了一类事物的共同属性和行为。在C++中,类的对象就是该类的某一特定实体(也称实例)。例如,将整个公司的雇员看作一个类,那么每一个雇员就是该类的一个特定实体,也就是一个对象。

实际上,每一种数据类型都是对一类数据的抽象,在程序中声明的每一个变量都是其所属数据类型的一个实例。如果将类看作是自定义的类型,那么类的对象就可以看成是该类型的变量。

声明一个对象和声明一个一般变量相同,采用以下的方式:

类名   对象名;

例如:

Clock myClock;

就声明了一个时钟类型的对象myClock。

注意  对象所占据的内存空间只是用于存放数据成员,函数成员不在每一个对象中存储副本。每个函数的代码在内存中只占据一份空间。

定义了类及其对象,就可以访问对象的成员,例如设置和显示对象myClock的时间值。这种访问采用的是”.“操作符,访问数据成员的一般形式是:

对象名.数据成员名

调用函数成员的一般形式是:

对象名.函数成员名(参数表)

例如,访问类Clock的对象的函数成员showTime()的方式如下:

myClock.showTime()

在类的外部只能访问到类的公有成员;在类的成员函数中,可以访问到类的全部成员。

4.类的成员函数

类的成员函数描述的是类的行为,例如时钟类的成员函数setTime()和showTime(),成员函数是程序算法的实现部分,是对封装的数据进行操作的方法。

4.1成员函数的实现

函数的原型声明要写在类体中,原型说明了函数的参数表和返回值类型,而函数的具体实现是写在类定义之外的。与普通函数不同的是,实现成员函数时要指明类的名称,具体形式为:

返回值类型  类名::函数成员名(参数表)

{

      函数体

}

例如:

void Clock::setTime(int newH,int newM,int newS)

{

      hour=newH;

      minute=newM;

      second=newS;

}

void Clock::showTime()

{

      cout<<hour<<":"<<minute<<":"<<second<<endl;

}

可以看出,与普通函数不同,类的成员函数名需要用类名来限制,例如”Clock::showTime“。

4.2成员函数调用中的目的对象

调用一个成员函数与调用普通函数的差异在于,需要使用”.“操作符指出调用所针对的对象,这一对象在本次调用中称为目的对象。例如使用myClock.showTime()调用showTime函数时,myClock就是这一调用过程中的目的对象。

在成员函数中可以不使用”.“操作符而直接引用目的对象的数据成员,例如上面的showTime函数中所引用的hour,minute,second都是目的对象的数据成员,以myClock.showTime()调用该函数时,被输出的是myClock对象的hour,minute,second属性。在成员函数中调用当前类的成员函数时,如果不使用”.“操作符,那么这一次调用所针对的仍然是目的对象。

在成员函数中引用其他对象的属性和调用其它对象的方法时,都需要使用”.“操作符。注意,在类的成员函数中,既可以访问目的对象的私有成员,又可以访问当前类的其他对象的私有成员。

4.3带默认形参值的成员函数

类的成员函数也可以有默认形参值,其调用规则与普通函数相同,类成员函数的默认值,一定要写在类定义中,而不能写在类定义之外的函数实现中。有时候这个默认值会带来很大的方便,比如时钟类的setTime()函数,就可以使用默认值如下:

class Clock

{

      public:

           void setTime(int new=0,int newM=0,int newS=0);

           ···

};

这样,如果调用这个函数时没有给出实参,就会按照默认形参值将时钟设置到午夜零点。

4.4内联成员函数

函数的调用过程要消耗一些内存资源和运行时间来传递参数和返回值,要记录调用时的状态,以便保证调用完成后能够正确地返回并继续执行。如果有的函数成员需要被频繁调用,而且代码比较简单,这个函数也可以定义为内联函数(inline function)。和普通内联函数相同,内联成员函数的函数体也会在编译时被插入到每一个调用它的地方。这样做可以减少调用的开销,提高执行效率,但是却增加了编译后的代码长度。所以要在权衡利弊的基础上慎重选择,只有对相对简单的成员函数才可以声明为内联函数。

内联函数的声明有两种方式:隐式声明和显式声明。

将函数体直接放在类体中,这种方法称之为隐式声明。比如,将时钟类的showTime()函数声明为内联函数,可以写作:

class Clock

{

      public:

           void setTime(int newH,int newM,int newS);

           void showTime(){

                     cout<<hour<<":"<<minute<<":"<<second<<endl;

           }

      private:

           int hour,minute,second;

};

为了保证类定义的简洁,可以采用关键字inline显式声明的方式。即在函数体实现时,在函数返回值类型前加上inline,类定义不加入showTime的函数体。请看下面的表达方式:

inline void Clock::showTime()

{

      cout<<hour<<":"<<minute<<":"<<second<<endl;

}

效果和前面隐式表达是完全相同的。

例   时钟类的完整程序

#include<iostream>
using namespace std;
class Clock{
public:
void setTime(int newH=0,int newM=0,int newS=0);
void showTime();
private:
int hour,minute,second;
};
void Clock::setTime(int newH,int newM,int newS)
{
hour=newH;
minute=newM;
second=newS;
}
inline void Clock::showTime()
{
cout<<hour<<":"<<minute<<":"<<second<<endl;
}
int main()
{
Clock myClock;
cout<<"First time set and output:"<<endl;
myClock.setTime();
myClock.showTime();
cout<<"Second time set and output:"<<endl;
myClock.setTime(8,30,30);
myClock.showTime();
return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值