|
|
|
《面向对象程序设计》自学方法指导 |
|
|
来源: 发布时间:2006-5-29 17:04:30 点击: |
<Ptr类型><Ptr名>= new <类型>[<数组大小>] 例如: float * real_ptr =new float[100]; 例中将real_ptr设置为指向新建数组的第-个元素,这个数组中含有100个实数,可以用名real-ptr[0],real-ptr[1],… real_ptr[99]分别访问。 当动态分配的内存不再需要时,应将其释放(比如放回堆,使它可以用于其他地方),使用运算符delete可以释放内存,这对于存放分配内存地址的指针很适用。 例如: delete num_ptr; 为了释放动态分配数织中所有元素的内存,有必要在字delete之后紧跟空的方括号[],例如:delete [ ] real_ptr; 当new为一个数组分配内存时,它保存了数组的大小,所以delete知道有多少个元素的内存需要释放,而不需要被明确告知。如果遗漏掉方括号[],将导致数组中仅有第一个元素的内存被释放! 虽然new和delete在上例中表现了很强的功用,但如果对有构造函数和析构函数对象,采用new和delete对其动态地分配和释放内存的话,new和delete将显示出更强大的功效。这将在后面的内容里进一步得到阐述。 4.类和对象 (1)类的定义 类的定义参照自学参考,从定义可以看出,一个类含有三部分,即私有部分、保护部分和公有部分。缺省时,在类中定义的项那是私有的。私有部分(private)的数据和函数只能被该类的成员访问;保护部分(Protected)的成员除可以被本类中的成品面致访问外,还可以被本类派生的类的成员函数访问;公有部分(public)的成员可以被本类之外的函数访问。 在定义类时,应明确几个概念。 ①对象:在C++中,对象(object)是声明为类类型的-个数据项,也就是说,对象是类的实际变量。正像定义int类型的变量-样,也可以定义类的变量。C++把类的变量叫做类的对象,对象也称为类的实例(inslance)。 可以用下面两种方法定义对象: (1)在定义类的同时,直接定义对象,即在定义类的有花括号"}"后直接写出属于该类对象名表列,各个对象间用逗号分开,最后加上分号。 (2)定义类之后,再定义该类的对象,一般格式如下: 类名 对象[,对象………]; 例如: Locationg A1,A2; 定义对象后,就可以使用基于对象的类的成员函效,其格式为 对象名.成员函数; 例如: A1.GetX(); ②类的作用域:作用域是指程序中标识符可以访问的区域,一般分为全局(global)和局部(1ocal)两种。作用域主要用来控制对标识符的访问,对于类来说,一个类的所有成员都在该类的作用域内;一个类的任何成员可以访问该类的其他任何成员。C++把类的所有成员都作为一个整体的相关部分。 一个类的成员函数可以不受限制地访问该类的数据成员,而在该类作用域之外对该类的数据和成员函数的访问则要受到一定的限制,有时甚至是不允许的。这体现了类的封装功能。 ③访问说明符:在类的定义中,用访问说明符来控制在类的作用域之外对类成员的可见性。在书中的例子里,类Location含有两个数据成员和三个成员函数。其中数据成员在私有部分(private)中定义,而成员函数则在公有部分(public)中声明。private和public就是访问说明符。在public部分列出的任何成员可以在程序的任何部分被访问;而private部分的成员只有在类的作用城内才可以存取。 作用域运算符和成员函数:成员函数也称之为方法,实际上,方法和成员函数指的是同一种实体,是一种实体两种不同的叫法。其中成员函数是程序设计语言C++中的术语,而方法则是面向对象方法学中的术语。在以后的叙述中,成员函数和方法是通用的。 从例2.2可以看出,在类Location的定义中有其成员函数的原型,这些原型与声明普通函数〔即非成员函数〕所用的语法完全相同。而方法的定义,既可以在类的定义内完成(称为内联函数),又可以在类定义之外进行(如例2.4);而且既可以和类定义放在同一个源文件中,也可以放在不同的源文件中。 大家已经看到,方法的定义与非成员函数的定义只在函数的头部有略微不同的格式。-般来说,如果类的方法的定义是在类的外部突现的,则在定义方法时必须把类名放在方法名之前,中间用作用域运算符(::)隔开。即: 类名::方法名; 这样即使几个类中的方法名完全相同,也可以用这种形式把他们完全区别开来。和普通函数一样,方法也应有返回值类型。 下面看一个例子://program example 参考1.1 #include <iostream.h> class C1 //定义第一个类 { private: int i; public: void set(int x); void print(); }; class C2 //定义第二个类 { private: int i; public: void set(int x); void print(); }; void C1::set(int x) { i=x; } void C1::print() { cout<<"in class C1 i="<<i<<endl; } void C2::set(int x) { i=x; } void C2::print() { cout<<"in class C2 i="<<i<<endl; } int main() { //分别定义和调用各个类的函数 C1 a; C2 b; a.set(100); b.set(200); a.print(); b.print(); } 程序的执行结果: in class C1 I=100 in class C2 I=200 该程序定义了两个类:C1和C2。每个类中有两个函效,其名字都是set和print。但由于使用了作用域运算符::,因而能明确地区分它们的操作。在main函数中,定义了c1的对象a和c2的对象b,分别调用各自的set函数相print函数。 ④成员函数的重载:简单地说,重载就是一词多义,C++中的重载分为函数重载和运算符重载,运算符的重载在以后再谈。所谓函数重载,就是几个不同的函数共用一个相同的名字,换言之,同一个函数名可以完成不同的操作。如果没有重载功能,则每个函数都必须有唯一的名字。例如C语言中的绝对值函数,由于返回值和形参的类型不同,绝对值函数的名字也不一样,其函数原型分别为: int abs(int I); long labs(long I); double fabs(double I); 这三个函数所执行的操作完全一样,只是返回值和参数类型不同,因此没有必要使用三个不同的函数名。在C++中,允许多个函数使用相同的函数名,这就是函数名重载。上述三个函数在C++中的原型分别为: int abs(int I) (1) long abs(long I) (2) double abs(double I) (3) 在一般情况下,可以根据上下文信息来区分重载函数的参数类型:这样,编译程序就能准确地辨明是哪一个函数的原型。上述三个函数的名字都是abs,即用同一个名字来表示三个不同的函数。尽管三个函数用的是同一个名字,但在调用时却很容易地根据上下文信息把它们区分开,因为函数中参数类型的具体值是不同的,编译程序可准确地作出判断而不会发生混乱。 对于自学资料中的例子,大家可以看到,在类的成员函数中,函数valueX()被重载了,两个函数的返回值和参数都不同,这样编译器很容易就知道调用的是哪一个函数。使用成员函数的重载要注意以下几点: ①重载函数应在参数个数或参数类型上有所不同.否则编译程序将无法选择,即使返回值不同也区分不开。例如: int func(int I) void func(int I) 这两个函数的返回值不同,而参数个数和类型完全相同,编译程序将无法区别这两个函数。 ②重载的成员函数应执行相同的功能。例如abs函数一般用来返回绝对值,如果让它返回平方根,则是不可取的。 ③成员函数的重载使用要适度。因为使用重载函数的目的是为了给功能略有不同的函数提供相同的名字,过多的使用会降低程序的可读性。 5.构造函数和析构函数: |
|
|
|