问题1:
利用域区分符我们可以在类定义的外部设置成员函数,但要注意的是,在类的内部必须预先声明:
void test::rp()
在函数类型的后面加上类的名称再加上
域区分符(:

再加函数名称,利用这样的方法我们就在类的外部建立了一个名为rp的test类大成员函数(方法),可能很多人要问,这么做有意义吗?在类的内部写函数代码不是更好?
答案是这样的:在类的定义中,一般成员函数的规模一般都比较小,而且一些特殊的语句是不能够使用的,而且一般会被
自动的设置成为inline(内联)函数,即使你没有明确的声明为inline,那么为什么有会被自动设置成为inline呢?因为大多数情况下,类的定义一般是放在头文件中的,在编译的时候这些函数的定义也随之进入头文件,这样就会导致被多次编译,如果是inline的情况,函数定义在
调用处扩展,就避免了重复编译的问题,而且把大量的成员函数都放在类中使用起来也十分不方便,为了避免这种情况的发生,所以c++是允许在外部定义类的成员函数(方法)的,将类定义和其它成员函数定义分开,是面向对象编程的通常做法,我们把类的定义在这里也就是头文件了看作是类的外部接口,类的成员函数的定义看成是类的内部实现。写程序的时候只需要外部接口也就是头文件即可,这一特点
和我们使用标准库函数的道理是一致的,因为在类的定义中,已经包含了成员函数(方法)的声明。
问题二
域区分符和外部全局变量和类成员变量之间的关系。
在上面的代码中我们看到了,外部全局和类内部都有一个叫做pp的整形变量,那么我们要区分操作他们用什么方法呢?
使用域区分符就可以做到这一点,在上面的代码中::pp=11;操作的就是外部的同名称全局变量,pp=100;操作的就是类内部的成员变量,这一点十分重要!
问题三
一个类的所有对象调用的都是同一段代码,那么操作成员变量的时候计算机有是如何知道哪个成员是属于哪个对象的呢?
这里牵扯到一个
隐藏的this指针的问题,上面的代码在调用a.rp()的的时候,系统自动传递一了个a对象的指针给函数,在内部的时候pp=100;的时候其实就是this->pp=100;
所以你把上面的成员函数写成如下形势也是正确的:
void test::rp()
{
::pp=11;
this->pp=100;
//this指针就是指向a对象的指针
}
类的成员函数和普通函数一样是可以进行重载操作的,关于重载函数前面已经说过,这里不再说明。
给出例子仔细看:
//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <
iostream>
using namespace std;
class test
{
private:
int number;
public:
float socre;
int pp;
public:
void rp(
int);
void rp(
float);
};
void test::rp(
int a)
//在外部利用域区分符定义test类的成员函数
{
cout<<"调用成员函数!a:"<<a<<endl;
}
void test::rp(
float a)
//在外部利用域区分符定义test类的成员函数
{
cout<<"调用成员函数!a:"<<a<<endl;
}
void main()
{
test a;
a.rp(100);
a.rp(3.14f);
cin.get();
}
下面我们来看一下利用指针和利用引用间接调用类的成员函数,对于对于指针和引用调用成员函数和调用普通函数差别不大,在这里也就不再重复说明了,注意看代码,多试多练习既可。
代码如下:
//程序作者:管宁
//站点:www.cndev-lab.com
//所有稿件均有版权,如要转载,请务必著名出处和作者
#include <
iostream>
using namespace std;
class test
{
private:
int number;
public:
float socre;
int pp;
public:
int rp(
int);
};
int test::rp(
int a)
//在外部利用域区分符定义test类的成员函数
{
number=100;
return a
+ number;
}
void run(test *p)
//利用指针调用
{
cout<<p->rp(100)<<endl;
}
void run(test &p)
//利用引用
{
cout<<p.rp(200)<<endl;
}
void main()
{
test a;
run(&a);
run(a);
cin.get();
}
前面我们说过,类的成员如果不显式的生命为public那么它默认的就是private就是私有的,私有声明可以保护成员不能够被外部访问,但在c++还有一个修饰符,它具有和private相似的性能,它就是protected修饰符。
在这里我们简单说明一下,他们三着之间的差别:
在类的private:节中声明的成员(无论数据成员或是成员函数)仅仅能被类的成员函数和友元访问。
在类的protected: 节中声明的成员(无论数据成员或是成员函数)仅仅能被类的成员函数,友元以及子类的成员函数和友元访问。
在类的public:节中声明的成员(无论数据成员或是成员函数)能被任何人访问。
由于private和protected的差别主要是体现在类的继承中,现在的教程还没有设计到友元和子类所以这里不做深入讨论,但上面的三点务必记得,在以后的教程中我们会回过头来说明的。
总的来说,类成员的保护无非是为了以下
四点!
1.相对与普通函数和其它类的成员函数来说,保护类的数据不能够被肆意的篡改侵犯!
2.使类对它本身的内部数据维护负责,只有类自己才能够访问自己的保护数据!
3.限制类的外部接口,把一个类分成公有的和受保护的两部分,对于使用者来说它只要会用就可以,无须了解内部完整结构,起到黑盒的效果。
4.减少类与其它代码的关联程,类的功能是独立的,不需要依靠应用程序的运行环境,这个程序可以用它,另外一个也可以用它,使得你可以轻易的用一个类替换另一个类。
下面为了演示类成员的保护特性,我们来做一个球类游戏!
我们设计一个类,来计算球员的平均成绩,要求在外部不能够随意篡改球员的平均成绩。
我们把该类命名为ballscore并且把它放到ballscore.h的有文件中!
--------------------------- ballscore.h-----------------------------
class ballscore
{
protected:
const static int gbs
= 5;
//好球单位得分
const static int bbs
= -3;
//坏球单位扣分
float gradescore;
//平均成绩
public:
float GetGS(
float goodball,
float badball)
//goodball为好球数量,badball为坏求数量
{
gradescore
= (goodball*gbs
+ badball*bbs) / (goodball
+ badball);
return gradescore;
//返回平均成绩
}
};
--------------------------------------------------------------------
主函数调用!
#include <
iostream>
#include "ballscore.h"
using namespace std;
void main()
{
ballscore jeff;
cout<<jeff.GetGS(10,3);
jeff.gradescore=5.5
//想篡改jeff的平均成绩是错误的!
cin.get();
}
在上面的代码中头文件和类的使用很好了体现了类的黑盒特性,谁也不能够在外部修改球员的平均成绩!
类体中的有一个地方要注意
const static int gbs = 5;//好球单位得分
const static int bbs = -3;//坏球单位扣分
之所以要修饰成const static 因为c++中类成员只有静态整形的常量才能够被初始化,到这里整个程序也就说完了,当然真正大比赛不可能是这样,只是为了说明问题就题命题而已,呵呵!