友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!阅读过程发现任何错误请告诉我们,谢谢!! 报告错误
喜书网 返回本书目录 我的书架 我的书签 TXT全本下载 进入书吧 加入书签

C语言实例教程(PDF格式)-第10章

按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!




作一个具有文件作用域的全局函数。  



同在类定义内部定义的成员函数一样,在函数外定义的成员函数一样 

可以直接的访问类中的数据成员和调用其它的成员函数,而无论它们 

本身是私有的还是公有的。但是,在类定义内部定义的成员函数和在 

类定义外部定义的成员函数还是有差别的。对于在类定义内部定义的 

成员函数,编译器总是将它作为一个内联函数来进行编译,无论你是 

否使用了inline关键字。而对于在类定义外部定义的成员函数,除非 

你显式使用了inline关键字,编译不会将它作为一个内联函数来编 

译。但如果加上了inline关键字,则编译器以同样的方式对待在类定 

义外部定义的成员函数。一般来说,对于比较短少的成员函数,在可 

能情况下,我们大多在类定义内部定义它们,而对于代码量比较大的 

成员函数,则几乎都是在类定义的外部来定义它们,否则,代码的可 

读性会变得很糟糕。  



  l 注意:  



  l 请仔细分析下面的代码 :  



    geti成员函数更好:  



      ° int geti()  



      ° {  


…………………………………………………………Page 53……………………………………………………………

  ° return i;  



  ° }  



       但是,对于一个结构庞大的对象,基于运行效率的考 

       虑,我们可以不得不返回指向成员的指针,因为当C++为 

       了返回对象时对这么一个庞大的对象的成员进行逐一拷 

       贝会需要大量的时间。当然,我们可以这样修改geti函 

       数:  



  ° const int* geti()  



  ° {  



  ° return &i;  



  ° }  



       但是用户使用下面的代码却是合法的:  



  ° int *i=(int*)myCls。geti();  



       我们没有办法强制使用类MyClass的编程者不这样做,尽 

       管我们建设他们不要这样做,但是,编程者应该知道由 

       此可能导致的后果。而我们也的确没有更好的办法来避 

       免出现这样的情况。即使我们愿意牺牲拷贝对象所耗费 

       的时间,在一些情况下,编程者仍然可以将函数的返回 

       值强制为一个引用,这时,由于C++编译所进行的优化, 

       我们仍然可能通过该引用来修改类中的私有成员的值。  



           



2。2。2 成员函数和this指针  



类的成员函数可以是静态的,也可以是非静态的。静态的成员函 

数和静态的成员变量以及它们之间的关系我们将在下一小节中讲 

述,对于非静态成员函数,由于它可以使用对象中的非静态数 

据,C++为类的每一个实例对象维护了不同的非静态数据成员,这 

样,我们很自然的想到一个问题,类的成员函数是如何区分不同 

的实例对象的数据成员的呢?事实上,对于每一个类的非静态成 

员函数,都有一个隐含的this指针,该指针指向调用该成员函数 

的实例对象。  


…………………………………………………………Page 54……………………………………………………………

当成员函数使用对象中的非静态成员(无论是成员变量还是成员函 

数),它事实上是通过this指针来调用该成员的。请看下面的代 

码:  



class MyClass  



{  



public:  



void seti(int newi)  



{  



i=newi;  



}  



private:  



int i;  



};  



对编译器而言,成员函数seti的定义事实上如下面的代码所示:  



void seti(int newi)  



{  



this…》i=newi;  



}  



对于以不同方式定义的成员函数,this指针具有不同的类型,在 

上面的seti函数中,this指针的类型为MyClass*                               const,这表 

明,this指针是一个常指针,程序中可能通过this指针来修改类 

中的成员的值,但不可以修改this指针本身的值,也就是说,不 

可以对this指针重新赋值,以使它指向另一个对象。  



假设我们在类MyClass定义了另一个成员函数geti,如下面的代码 

所示:  



int geti() const  



{  



return i;  


…………………………………………………………Page 55……………………………………………………………

}  



在上面的代码中,const关键字表明函数geti不会修改调用该成员 

函数的实例对象中的成员的值。对于编译器而言,上面的成员函 

数geti是这样的:  



int geti() const  



{  



return this…》i;  



}  



由于使用了const关键字,则this指针的类型为const                                  MyClass*  

const,这表明不但不能修改this指针本身,也不能通过this指针 

修改对象中的成员。举一个例子,如果我们按如下方式定义seti 

函数:  



void seti(int newi) const  



{  



i=newi;  



}  



上面的代码将会导致编译错误 “l…value                             specifies        const  

object”。  



一般情况下我们不需要显式地使用this指针。下面的代码显示了 

this指针的一个典型应用:  



#include   



#include   



#include   



class MyPosition;  



class MyScreen  



{  



public:  



void PrintMyPosition(MyPosition* pMyPosition);  


…………………………………………………………Page 56……………………………………………………………

};  



class MyPosition  



{  



public:  



int x;y;  



void DisplayMyPosition(MyScreen* pMyScreen);  



};  



void MyScreen::PrintMyPosition(MyPosition* pMyPosition)  



{  



HANDLE hConsoleOutput=GetStdHandle(STD_OUTPUT_HANDLE);  



COORD dwCursorPosition={0; 24};  



char sz'80';  



sprintf(sz; 〃My position is (%d;%d)。〃; pMyPosition…》x; pMyPosition…》y);  



DWORD cWritten;  



WriteConsoleOutputCharacter(hConsoleOutput; sz; lstrlen(sz);   



dwCursorPosition; &cWritten);  



dwCursorPosition。X=pMyPosition…》x;  



dwCursorPosition。Y=pMyPosition…》y;  



SetConsoleCursorPosition(hConsoleOutput;dwCursorPosition);  



}  



void MyPosition::DisplayMyPosition(MyScreen* pMyScreen)  



{  



pMyScreen…》PrintMyPosition(this);  



}  



void main()  



{  


…………………………………………………………Page 57……………………………………………………………

MyPosition mypos;  



MyScreen mysrn;  



coutx》》y;  



mypos。x=x;  



mypos。y=y;  



mypos。DisplayMyPosition(&mysrn);  



}  



请注意类MyPosition的DisplayMyPosition成员函数,它使用一个 

指向MyScreen对象的指针作为参数。在DisplayMyPosition成员函 

数的实现中,调用了MyScreen对象的PrintMyPosition成员函数, 

PrintMyPosition成员函数需要一个指向MyPosition对象的指针作 

为其参数,这里,我们希望将指向调用DisplayMyPosition成员函 

数的对象本身的指针作为参数进行传递,这时就必须使用this指 

针。将指向对象自身的指针作为参数传递给其它函数,在实际编 

程中是一个很常用的技巧,在这些场合,this指针得到了广泛的 

运用,在以后编程的过程中,我们会经常看到这样的用法。  



除了示范this指针的用法以外,上面的代码还示范了如何在控制 

台窗口中定位输出字符串的位置。运行上面的程序,它首先要求 

用户输入一个坐标值,然后,在屏幕的最底行 (这里假定用户使用 

80'    25的控制台窗口大小),最后,将下一次显示输出的位置定 

位于用户所输入的坐标值所指定的点。整个程序运行的结果如图 

所示。  


…………………………………………………………Page 58……………………………………………………………

                                              



                 图2。3 在控制台窗口中进行定位  



  ° 注意:  



  ° 上面的程序代码不能在MS…DOS环境下进行编译和链接,因为 

   我们在程序中显式的调用了Win32控制台API函数 (如 

   SetConsoleCursorPosition和WriteConsoleOutputCharacter 

   等),它们属于Win32应用程序接口的一部分。为了使用这些 

    函数,我们在程序的最开始包含了头文件windows。h。因此, 

   上面的程序尽管具有和普通的MS…DOS环境下的C/C++程序代码 

   相一致的结构,但它是一个Windows应用程序,只能运行于32 

   位Windows环境。我们可以从上面的函数中看出Win32控制台 

   应用程序和传统的MS…DOS字符模式应用程序之间的本质 区 

    别。  



    



2。2。3 静态成员  



前面说过,无论是类中的成员变量还是成员函数,都可以声明为 

静态的。类的静态成员在工作起来和非静态成员有很大的差别, 

因此我们在这里用单独的一个小节来讲述它们。  



先看一个静态数据成员的例子。  



#include   



class MyClass  



{  


…………………………………………………………Page 59……………………………………………………………

public:  



static int i;  



};  



int MyClass::i;  



void main()  



{  



MyClass cls1;  



MyClass cls2;  



cls1。i=1;  



cout
返回目录 上一页 下一页 回到顶部 0 0
未阅读完?加入书签已便下次继续阅读!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!