按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 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