Presentation is loading. Please wait.

Presentation is loading. Please wait.

第 4 章 类的高级部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院.

Similar presentations


Presentation on theme: "第 4 章 类的高级部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院."— Presentation transcript:

1 第 4 章 类的高级部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院

2 主要内容 4.1 静态成员 4.2 友元 4.3 对象赋值问题 4.4 拷贝构造函数 4.5 运算符重载 4.6 对象组合

3 4.1 静态成员 例:一个学生类,定义其对象张三、李四,他们分别维护着类成员的一份副本(学号、姓名、籍贯等)。 如果要统计一个班学生总数?
4.1 静态成员 例:一个学生类,定义其对象张三、李四,他们分别维护着类成员的一份副本(学号、姓名、籍贯等)。 如果要统计一个班学生总数? 用类外的变量记录,违背了数据封装。 用类的一个数据成员记录,导致多个副本,不仅冗余,而且势必造成数据不一致。 全局对象不好,但复杂程序都是由许多程序员共同设计的,因此需要这种性质的对象。 使用类中的静态数据成员——解决访问权限控制问题。 使用静态成员函数——解决操作合法性控制问题。

4 4.1.1 静态数据成员 1. 用关键字static声明; 2. 同一个类中的所有对象都共享该变量;
静态数据成员 1. 用关键字static声明; 2. 同一个类中的所有对象都共享该变量; 3. 必须在类外定义和初始化,用(::)来指明所属的类。 4. 静态变量不依赖于对象而存在,无论是否定义该类的对象,这种类型的变量都存在。静态数据成员实际上是在类外定义的一个变量,它的生存期和整个程序的生存期一样,在定义对象之前,静态数据成员就已经存在。

5 class StaticDemo { static int x ; int y ; public: void putx( int a){ x=a ; } void puty( int b ){ y=b ; } int getx( ) { return x ; } int gety( ) { return y ; } } ; int StaticDemo::x ;

6 // 静态变量x将被StaticDemo类的所有对象共享,例如:
StaticDemo obj1, obj2 ; obj1.putx(5) ; obj1.puty( l0 ) ; obj2.puty(20 ) ; cout << "x: "<< obj1.getx( ) << " " << obj2.getx( ) << endl ; cout << "y: "<< obj1.gety( ) <<" "<< obj2.gety( ) << endl ;

7 4.1.2 静态函数成员 静态函数成员是类中的一个函数,有static修饰。
静态函数成员 静态函数成员是类中的一个函数,有static修饰。 静态函数成员和静态数据成员类似,在对象生成之前也已经存在。这就是说在对象产生之前,静态的函数成员就能访问其它静态成员。 类外代码可以使用类名和作用域操作符来调用静态成员函数。 静态成员函数只能引用属于该类的静态数据成员或静态成员函数。见例【例4-2】。 注意: #include <iostream.h> class StatDemo { static int x; int y; public: StatDemo(int y=0){ this->y=y; x++; } int getx( ) { return x; } int gety( ) { return y; } static void print( ){ // new function cout<< x<<endl; }; int StatDemo::x=0; // definition & initialization void main( ) { StatDemo o1(10),o2; cout<<o1.getx( )<<endl; StatDemo::print( ); o1.print( );

8 办公室预算 子公司1预算 子公司2预算 子公司3预算 子公司4预算

9 // budget2.h文件的内容 。 class Budget { static float corpBudget; float divBudget; public: Budget( ) { divBudget = 0; } void addBudget( float b) { divBudget += b; corpBudget += divBudget; } static void mainOffice( float ); float getDivBudget( ) { return divBudget; } float getCorpBudget( ){ return corpBudget;} };

10 // Contents of budget2.cpp
#include "budget2.h" float Budget::corpBudget = 0 ; // Definition of static member function. void Budget::mainOffice(float moffice) { corpBudget += moffice; }

11 //主程序pr4-2.cpp的内容 #include " budget2.h“ void main( ) { float amount; int i; float bud; cout << "Enter main office's budget request: "; cin >> amount; Budget::mainOffice(amount); Budget divisions[4];

12 for ( i = 0; i < 4; i++) { cout << "Enter the budget for Division "; cout << (i + 1) << " " ; cin >> bud; divisions[i].addBudget(bud); } cout << "\n Here are the division budget :\n"; { cout << "\t Division" << (i + 1) << "\t $ "; cout << divisions[i].getDivBudget( ) << endl;

13 budget2.h budget2.cpp 4-2.cpp
cout << "\t Total Requests: "; cout << divisions[0].getCorpBudget( ) << endl; } budget2.h budget2.cpp cpp 1. 对于静态的函数成员,是通过类名和作用域分辨符调用的。 2. 也可以采用对象点的方式调用

14 4.2 友元函数 引入友元的原因? 1. 友元函数不是类中的函数成员,但它和类的函数成员一样,可以访问类中定义的私有成员。
4.2 友元函数 引入友元的原因? 1. 友元函数不是类中的函数成员,但它和类的函数成员一样,可以访问类中定义的私有成员。 2. 友元函数可以是一个外部函数,也可以是另外一个类的函数成员。 3. 将某个函数声明为一个类的友元方式,前面加friend 。

15 4.2.1 外部函数作为类的友元 【补例】求两个点之间的距离。 class Point { int xPos, yPos ; public:
外部函数作为类的友元 【补例】求两个点之间的距离。 class Point { int xPos, yPos ; public: Point(int xx=0, int yy=0 ) { xPos=xx; yPos=yy; } int GetXPos( ) { return xPos; } int GetYPos( ) { return yPos; } friend double Distance(Point &a, Point &b); };

16 double Distance( Point & a, Point & b) { double dx=a.xPos-b.xPos;
double dy=a.yPos-b.yPos; return sqrt(dx*dx+dy*dy); } void main( ) Point p1(3, 5), p2(4, 6); cout<< Distance(p1, p2) <<endl; 不采用友元如何解决?

17 4.2.2 类的成员函数作为另外一个类的友元 其他类的成员函数声明为一个类的友元函数,这个成员函数也称为友元成员。
类的成员函数作为另外一个类的友元 其他类的成员函数声明为一个类的友元函数,这个成员函数也称为友元成员。 友元成员不仅可以访问自己所在类对象中的私有成员和公有成员,还可以访问friend声明语句所在类对象中的私有成员和公有成员,这样能使两个类相互合作完成某一任务。 例:将Aux类的函数addBudget声明为Budget类的友元函数。 Auxiliary

18 办公室预算 子公司1预算 辅助办公室预算 子公司2预算 辅助办公室预算 子公司3预算 辅助办公室预算 子公司4预算 辅助办公室预算

19 class Budget ; // 对Budget类超前使用说明
class Aux // Aux类的定义 { private: float auxBudget ; public: Aux( ) { auxBudget = 0 ; } void addBudget( float , Budget & ) ; float getDivBudget( ) { return auxBudget ; } } ;

20 class Budget // Budget class declaration
{ static float corpBudget; float divBudget; public: Budget( ) { divBudget = 0; } void addBudget(float B) { divBudget += B; corpBudget += divBudget; } float getDivBudget( ) { return divBudget; } float getCorpBudget( ) { return corpBudget; } static void mainOffice( float ); friend void Aux::addBudget(float, Budget &); };

21 // Contents of budget3.cpp
#include "budget3.h" // Definition of static member of Budget class float Budget::corpBudget = 0; // Definition of static member function mainOffice. void Budget::mainOffice(float moffice ) { corpBudget += moffice; }

22 // Definition of member function mainOffice.
// Contents of auxi1.cpp #include "auxi1.h" #include "budget3.h" // Definition of member function mainOffice. void Aux::addBudget(float b, Budget &div) { auxBudget += b; div.corpBudget += auxBudget; } 注意!

23 // Contents of main program
#include "budget3.h“ void main( ) { float amount; int i; float bud; cout << "Enter the main office's budget: "; cin >> amount; Budget::mainOffice(amount); Budget divisions[4]; Aux auxOffices[4];

24 for (i = 0; i < 4; i++) { cout << "Enter the budget request for division "; cout << (i + 1) << ": "; cin >> bud; divisions[i].addBudget(bud); cout << "Enter the budget request for division"; cout << (i + 1) << "'s auxiliary office: "; auxOffices[i].addBudget(bud, divisions[i]); }

25 cout << "Here are the division budget requests:\n";
for (i = 0; i < 4; i++) { cout << "\tDivision " << (i + 1) << "\t\t\t "; cout << setw(7); cout << divisions[i].getDivBudget( ) << endl; cout << "\tAuxilary Office of Division " <<(i+1); cout << "\t"; cout << auxOffices[i].getDivBudget( ) << endl; } cout << "\tTotal Requests (including main office):"; cout << divisions[0].getCorpBudget( ) << endl; auxi1.h budget3.h auxi1.cpp budget3.cpp cpp

26 4.2.3 一个类作为另外一个类的友元 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。 class A
一个类作为另外一个类的友元 若一个类为另一个类的友元,则此类的所有成员都能访问对方类的私有成员。 class A { int x; friend class B; public: void Display( ){ cout<<x<<endl;} } ; class B { A a; void Set(int i) { a.x = i; } void Display( ) { a.Display( ); } };

27 4.3 对象赋值问题 采用赋值运算符“=”可以将一个对象赋值给另外一个对象,或者采用一个对象初始化另外一个对象。在缺省情况下,这两个操作执行的是对象成员之间的拷贝,也称为按位拷贝或浅拷贝。 【例4-4】对象赋值(浅拷贝)。

28 class Rectangle { float width , length , area; void calcArea( ) { area = width * length; } public: void setData(float w, float l) { width = w; length = l; calcArea( ); } float getWidth( ) { return width; } float getLength( ) { return length; } float getArea( ) { return area; } };

29 cout << "\n Box l's Area: "<< box1.getArea( );
void main( ) { Rectangle box1, box2; box1.setData(10, 20); box2.setData(5, 10); cout << "\n Box l's Area: "<< box1.getArea( ); cout << "\n Box 2's Area: "<< box2.getArea( ); box2 = box1; // 对象赋值 } 4-4.cpp

30 4.3 对象赋值问题(continued) 当采用一个对象初始化另一个对象时,对象成员之间的赋值也是按位拷贝。
赋值和初始化的区别:赋值出现在两个对象都已经存在的情况下,而初始化出现在创建对象时,例如: Rectangle box1; box1. setData(100, 50); Rectangle box2 = box1; // initialization

31 4.4 拷贝构造函数 拷贝构造函数是一个特殊的构造函数,当定义一个对象并采用同类型的另外一个对象初始化时,将自动调用拷贝构造函数。
4.4 拷贝构造函数 拷贝构造函数是一个特殊的构造函数,当定义一个对象并采用同类型的另外一个对象初始化时,将自动调用拷贝构造函数。 通常,采用缺省的按位拷贝操作也能正确地实现赋值,但在某些情况下不能正确执行。 Example:

32 PersonInfo(char *n, int a) { name = new char[strlen(n) + 1];
class PersonInfo { char *name; int age; public: PersonInfo(char *n, int a) { name = new char[strlen(n) + 1]; strcpy(name, n); age = a; ~PersonInfo ( ) { delete [ ] name; } char *getName ( ) { return name; } int getAge ( ) { return age; } }; PersonInfo person1("Jones", 20); PersonInfo person2 = person1; // 将产生??? 可以运行该程序给学生看结果,分析原因。引入拷贝构造函数的解决方法

33 PersonInfo (PersonInfo &ob j)
1. 解决的方法:定义拷贝构造函数。 2. 拷贝构造函数是一个特殊的构造函数,当采用一个对象初始化另一个对象时,将自动调用该函数。 PersonInfo (PersonInfo &ob j) { name = new char [strlen(obj .name) + 1]; strcpy(name, obj.name); age = obj.age; } 拷贝构造函数的参数代表“=”运算符右边的对象: PersonInfo person2 = person1 ;

34 进一步演化:Using const Parameters
PersonInfo ( const PersonInfo &ob j) { name = new char [strlen(obj .name) + 1]; strcpy(name, obj.name); age = obj.age; }

35 4.4.1 缺省的拷贝构造函数 如果一个类没有定义拷贝构造函数,C++将为其创建一个缺省的拷贝构造函数。
缺省的拷贝构造函数 如果一个类没有定义拷贝构造函数,C++将为其创建一个缺省的拷贝构造函数。 缺省的拷贝构造函数的功能就是按位赋值。

36 4.4.2 调用拷贝构造函数的情况 用对象初始化同类的另一个对象(P129)。 例如:
调用拷贝构造函数的情况 用对象初始化同类的另一个对象(P129)。 例如: PersonInfo st1("ZhangSan" , 20 ); PersonInfo st2( st1) , st3 = st1 ;

37 2. 如果函数的形参是对象,当进行参数传递时将调用拷贝构造函数(P129) 。
void changePerson ( PersonInfo p ) { //… }   void main ( ) { PersonInfo st1("Susan" , 20 ) ; changePerson ( st1 ) ; 思考:为什么拷贝构造函数的参数一定是个引用,而不是对象?

38 3. 如果函数的返回值是对象,函数执行结束时,将调用拷贝构造函数对无名临时对象初始化(P129) 。 class PersonInfo {
public: PersonInfo ( ) { cout<<"调用构造函数\n" ; } PersonInfo (PersonInfo &obj ){ cout<<"调用拷贝\n" ; } ~PersonInfo ( ) { cout<<"调用析构函数\n" ; } } ;  PersonInfo getPerson ( ) { PersonInfo person ; return person ; // 函数的返回值是对象 }  void main ( ) { PersonInfo student ; student = getPerson ( ) ; 4-5.cpp

39 注意:VC 2005 版本有问题,VC6正确。

40 如果函数返回值是对象,要考虑return语句的效率。
例如: return string(s1 + s2); 表示“创建一个无名的临时对象并且将它返回” 与“先创建一个局部对象temp并返回”不等价: string temp(s1 + s2); return temp;

41 4.4.3 拷贝构造函数中的常参数 // 拷贝构造函数的参数为常引用 PersonInfo( const PersonInfo &obj )
拷贝构造函数中的常参数 // 拷贝构造函数的参数为常引用 PersonInfo( const PersonInfo &obj ) { name = new char [ strlen( obj.name ) + 1 ] ; strcpy( name, obj.name ) ; age = obj.age ; } 功能:防止程序员无意间修改参数对象。

42 补充:编译器的一个纰漏 class InvoiceItem { public: InvoiceItem( int size = 51)
{ cout << "调用缺省构造函数!\n"; } InvoiceItem( char *d ) { cout << "调用一个参数的构造函数!\n"; } InvoiceItem( char *d , int u) { cout << "调用两个参数的构造函数!\n"; } InvoiceItem( InvoiceItem & obj ) { cout << "调用拷贝构造函数!\n"; } ~InvoiceItem( ) { cout << "调用析构函数!\n"; } } ;

43 补充:编译器的一个纰漏 注意:VC 2005 和 VC6 都不正确。 int main( ) {
InvoiceItem Inventory[5]={ // 对象数组 InvoiceItem("鼠标", 100), // A 行 InvoiceItem("硬盘"), // B 行 "主板", // C 行 99 // D 行 } ; return 0; } 4-6.cpp 注意:VC 和 VC6 都不正确。

44 4.5 运算符重载 Example 1: The / operator can perform two types of division: floating point and integer. Example 2: Date today( 2016, 6, 7); today.add (5); today += 5; // ???

45 4.5.1 重载赋值运算符 如果对象中有指针成员,采用拷贝构造函数能解决对象初始化问题,但并不能处理对象赋值。 Example:
重载赋值运算符 如果对象中有指针成员,采用拷贝构造函数能解决对象初始化问题,但并不能处理对象赋值。 Example: 假设 PersonInfo 具有拷贝构造函数: PersonInfo person1("ZhangSan” , 20 ) , person2("John",24) ; person2 = person1; // memberwise assignment

46 Overload the = operator :
class PersonInfo { char *name; int age; public: … … void operator = (const PersonInfo &right) { delete [ ] name; name = new char[strlen(right.name) + 1]; strcpy(name, right.name); age = right.age; } };

47 operator= 函数的参数不一定是常引用,上述声明优点 :
(1) 效率高。采用引用可以防止参数传递时生成对象拷贝,节省了对象初始化和析构的过程。 (2) 将参数声明为const,可以防止函数无意间修改对象right的内容。 (3) 符合赋值运算的常识。 函数调用: p2.operator = (p1);  p2 = p1; p3 = p2 = p1; // ???

48 4.5.2 this指针 this是一个隐含的内嵌指针,它指向调用成员函数的当前对象。 Example:
cout << person1.getName( ) << endl; cout << person2.getName( ) << endl;

49 【例4-7】 class PersonInfo { char *name; int age; public: PersonInfo operator=(const PersonInfo &right) { delete [ ] name; name = new char[strlen(right.name)+ 1]; strcpy(name, right.name); age = right.age; return *this; } // 其他函数略 };

50 PersonInfo jim("Jim", 20), bob("Bob", 21), clone = jim;
void main( ) { PersonInfo jim("Jim", 20), bob("Bob", 21), clone = jim; clone = bob = jim; // Call overloaded = operator cout<< clone.getName( )<< ", " << clone.getAge( )<<endl; } operator=还有问题吗?

51 PersonInfo &operator=( const PersonInfo &right )
{ // 重载运算符“=”的秘笈: // 一、检查自赋值 if( this == &right ) return *this; // 二、释放原有的内存空间 delete [ ] name ; // 三、分配新的内存空间,并复制内容 name = new char[ strlen(right.name )+ 1] ; strcpy( name, right.name ) ; age = right.age ; // 四、返回本对象的引用 return *this ; }

52 this指针是以隐含参数的形式传递给非静态的函数成员:
PersonInfo(PersonInfo *this, char *name, int age ) { this->name = new char[ strlen( name ) + 1] ; strcpy( this->name, name ) ; this->age = age ; }

53 4.5.4 重载双目算术运算符 引入原因: Feetinches length1(3,5), length2(6,3), length3;
重载双目算术运算符 引入原因: Feetinches length1(3,5), length2(6,3), length3; length3 = length1 + length2; // 等价于 length3 = length1.operator + ( length2 ); 仅讲述如何重载双目运算符+和-,其它类似。

54 class FeetInches { int feet, inches; void simplify( ); public: // 其他函数代码见4.5.3节 … … FeetInches operator + (const FeetInches &); FeetInches operator - (const FeetInches &); };

55 // Overloaded binary + operator.
FeetInches FeetInches::operator + ( const FeetInches &right ) { FeetInches temp; temp.inches = inches + right.inches; temp.feet = feet + right.feet; temp.simplify( ); return temp; }

56 // Overloaded binary - operator.
FeetInches FeetInches::operator - ( const FeetInches &right) { FeetInches temp; temp.inches = inches - right.inches; temp.feet = feet - right.feet; temp.simplify( ); return temp; }

57 4.5.4 重载双目算术运算符 任何一个双目算术运算符B被重载以后,当执行二元运算时: Obj1 B Obj2
重载双目算术运算符 任何一个双目算术运算符B被重载以后,当执行二元运算时: Obj1 B Obj2 完全等价于:Obj1.operator B( Obj2 )

58 4.5.5 重载单目算术运算符 Example 1: distance2 = ++distancel; // 前置++ 等价于:
重载单目算术运算符 Example 1: distance2 = ++distancel; // 前置++ 等价于: distance2 = distancel.operator ++ ( ); Example 2: distance2 = distancel++; // 后置++ distance2 = distancel.operator ++ (0);

59 FeetInches operator + (const FeetInches &);
class FeetInches { int feet, inches; void simplify( ); public: … … FeetInches operator + (const FeetInches &); FeetInches operator - (const FeetInches &); FeetInches operator++( ); FeetInches operator++( int ); }; Dummy parameter

60 // Overloaded prefix ++ operator.
FeetInches FeetInches::operator++( ) { ++inches; simplify ( ); return *this; }

61 // Overloaded postfix ++ operator.
FeetInches FeetInches::operator++(int) { FeetInches temp(feet, inches); inches++; simplify( ); return temp; }

62 if ( distancel < distance2)
重载关系运算符 重载关系运算符,实现两个对象的比较,其中关系运算符函数要返回一个布尔值(true或false) : Example: if ( distancel < distance2) { ... code ... }

63 bool operator> (const FeetInches & );
class FeetInches { int feet , inches; void simplify( ); public: … … bool operator> (const FeetInches & ); bool operator< (const FeetInches & ); bool operator==(const FeetInches & ); };

64 // Overloaded > operator.
bool FeetInches::operator > ( const FeetInches &right ) { if (feet > right.feet) return true; else if (feet==right.feet && inches> right.inches) else return false; }

65 // Overloaded < operator.
bool FeetInches::operator < ( const FeetInches &right) { if (feet < right.feet) return true; else if (feet == right.feet && inches < right.inches) return true; return false; }

66 // Overloaded == operator.
bool FeetInches::operator==( const FeetInches &right) { if (feet == right.feet && inches == right.inches) return true; else return false; }

67 4.5.6 重载流操作符<<和>>
重载流操作符<<和>> Example: int value ; cin >> value; cout << value ; FeetInches distance ; cin >> distance; cout << distance; 注意:如果要为FeetInches类重载流插入符<<,那么必须通过友元函数的形式实现函数重载。 能否实现?

68 class FeetInches { int feet , inches; public: … … friend ostream &operator<<( ostream &, FeetInches &); friend istream &operator>>( istream &, };

69 // Overloaded << operator.
ostream &operator<<( ostream &strm, FeetInches &obj) { strm << obj.feet << "feet, " << obj.inches <<" inches"; return strm; }

70 // Overloaded >> operator.
istream &operator>>( istream &strm, FeetInches &obj) { cout << "Feet: " ; strm >> obj.feet; cout << "Inches: "; strm >> obj.inches; return strm; }

71 cout << distance1 <<" "<< distance2 << endl ;
等价于如下过程: 1. 首先调用重载函数<<,执行cout << distancel,返回cout对象; 2. 执行cout << “ ”,返回值是cout对象; 3. 以(1)的方式,执行cout << distance2; 4. 以(2)的方式,执行表达式中的cout << endl; 4-g.cpp

72 4.5.8 重载类型转换运算符 Example: int i=100; float f=3.14f; i=f; f=i;
重载类型转换运算符 Example: int i=100; float f=3.14f; i=f; f=i; 对于一个对象,通过重载类型转换函数,可实现类型转换功能。

73 // Truncates the inches value operator int( ) { return feet; } };
No return type is specified in the function header. Since the function is a FeetInches-to-float conversion function, it will always return a float. class FeetInches { int feet , inches; public: … … operator float( ); // Truncates the inches value operator int( ) { return feet; } };

74 // Convert a FeetInches object to a float.
FeetInches::operator float( ) { float temp = feet; temp += (inches / 12.0f); return temp; }

75 { FeetInches distance; float f; int i; cin >> distance;
void main( ) { FeetInches distance; float f; int i; cin >> distance; f = distance; i = distance; } 4-8.cpp

76 4.5.8 重载[ ]操作符 Example 1: string name = "John"; cout << name[0];
重载[ ]操作符 Example 1: string name = "John"; cout << name[0]; name[0]='a'; C++除了支持重载传统的运算符,还支持重载[ ] 符。这样就能象操作普通数组一样操作对象数组。

77 class IntArray { int *aptr; int arraySize; void memError( ); void subError( ); public: IntArray( int ); IntArray( const IntArray & ); ~IntArray( ); int size( ) { return arraySize; } int &operator[ ]( const int & ); }; why?

78 // Constructor for IntArray class
IntArray::IntArray( int s ) { arraySize = s; aptr = new int [s]; if (aptr == 0) memError( ); for (int i = 0; i < arraySize; i++) *(aptr + i) = 0; }

79 // Copy Constructor for IntArray class.
IntArray::IntArray(const IntArray &obj) { arraySize = obj.arraySize; aptr = new int [arraySize]; if (aptr == 0) memError ( ); for(int i = 0; i < arraySize; i++) *(aptr + i) = *(obj.aptr + i); }

80 // Destructor for IntArray class.
IntArray::~IntArray( ) { if (arraySize > 0) delete [ ] aptr; arraySize=0; }

81 // memError function. void IntArray::memError( ) { cout << "Cannot allocate memory. \n"; exit(0); } // subError function. void IntArray::subError( ) cout << "Subscript out of range. \n";

82 // Overloaded [ ] operator.
int & IntArray::operator[ ] (const int &sub) { if ( sub<0 || sub >= arraySize) subError( ); return aptr[sub]; }

83 cout << table[x] << " " ; cout << endl;
void main( ) { IntArray table(10); int x; for ( x = 0; x < 10; x++) table[x] = table[x] + 5; cout << table[x] << " " ; cout << endl; cout << "store a value in table[11].\n"; table[11] = 0; } 思考:由于table[x] 重载时为一个引用,如果[]中是一个2+1似的表达式,那么为什么也可以? 4-9.cpp

84 4.5.9 重载运算符时要注意的问题 通过运算符重载,虽然可以改变运算符的原义,但最好不要改变。
重载运算符时要注意的问题 通过运算符重载,虽然可以改变运算符的原义,但最好不要改变。 运算符重载不能改变运算符原来要求的参数个数。 尽管可以重载C++中的大部分运算符,但有些运算符是不允许重载的。

85 The operators that cannot be overloaded:
?: * :: sizeof operators that may be overloaded: + - * / % ^ & | ~ ! = < > += -= *= /= %= ^= &= |= << >> >>= <<= == != <= >= && || >* , -> [ ] ( ) new delete

86 4.5.10 运算符重载综合举例 —自定义string类
自动实现内存的动态分配,程序员无须关心为一个数组要分配多少个字节的空间; 可将string对象直接赋给MyString对象; 采用+=操作符可以连接两个MyString对象; 采用= =、<、>和!=操作符可以实现两个对象的比较,无须调用strcmp函数; 可模仿该类,增加新的重载函数,实现新功能。 自学该节。

87 4.6 对象组合 结构体支持嵌套,即在定义一个结构体类型时,可以嵌套结构体类型的变量。
4.6 对象组合 结构体支持嵌套,即在定义一个结构体类型时,可以嵌套结构体类型的变量。 类也可以出现这种情况,即让某个类的对象作为另一个类中的数据成员出现,这就是对象组合。 构造函数调用顺序:先调用内嵌对象的构造函数(按内嵌时的声明顺序,先声明者先构造)。然后调用本类的构造函数。(析构的顺序相反) 若调用缺省构造函数(即无形参的),则内嵌对象的初始化也将调用相应的缺省构造函数。 4-h.cpp

88 Account savings ; //储蓄账户 Account check ; //支票账户
class Customer { public: MyString name ; MyString address ; MyString city ; MyString state ; MyString zip ; Account savings ; //储蓄账户 Account check ; //支票账户 Customer( char *n , char *a , char *c , char *s , char *z ) : name(n) , address(a), city(c), state(s), zip(z) { } } ;

89 int main( ) { Customer ZhangSan( "Zhang San", "YuDao Street 29", "Nanjing", "Jiangsu", "210016") ; ZhangSan.savings.makeDeposit(1000 ) ; ZhangSan.check.makeDeposit(500 ) ; }


Download ppt "第 4 章 类的高级部分 陈哲 副教授 南京航空航天大学 计算机科学与技术学院."

Similar presentations


Ads by Google