在学习C++类的定义之前,先要知道一个类的成员与成员函数所具有的访问权限问题,也就是通常说的访问修饰符。
C++中,对类的成员和成员函数进行访问权限的设置时,具有默认、public、private和protected四种访问修饰符,简单介绍如下:
默认情况下,不加任何修饰,它表示该类的成员或成员函数是私有的,即与private等价。
public是公共访问修饰符,它所修饰的成员或者成员函数,不仅该类内部的其他成员函数可以访问由public修饰的成员或者成员函数,而且不属于该类的其他类的成员或者成员函数都可以访问。
private是私有访问修饰符,它所修饰的成员或者成员函数,对于该类来说是可以随意访问,即该类的任何成员函数都可以访问;但是对于不属于该类的成分,例如另一个其它的不同的类,没有任何权限访问,也就是说这个其他类根本看不到。另外,甚至对该类的派生类也不能够访问到该类的私有成员或成员函数。
protected是受保护修饰符,它所修饰的成员或者成员函数,对于该类及其该类的派生类来说,都是可以访问的,而对于除了该类和该类的派生类以外的其它任何类都没有权限访问。
关于对类的成员或成员函数进行访问的问题,C++中还可以定义友元函数,这就为外部另一个函数可以访问该类的成员函数提供了可能,从而通过成员函数间接操作类的数据成员,这也应该算是一种访问修饰符。
下面定义并实现一个C++类,类名称为Filter。对于Filter类,设计思想如下:
该类包含一个区间,作为类的私有数据成员,包括区间的下界lower_limit和上界upper_limit,另外,为了实现Filter类的过滤功能,假设扫描某个字符串,统计某个字符在一个容器中每个字符串中出现的次数,再定义一个字符成员some_char。
关于类的行为,假设存在一个过滤的行为,由函数filter来实现,可见它应该是public公共的,同时对于扫描一个字符串并统计指定字符出现的次数,是类的内部使用的函数,假设为scan,并声明为private私有的。
根据上面的描述,定义类如下所示:
#include <iostream>
#include <string>
#include <vector>
using namespace std;
class Filter {
public:
Filter();
Filter(const char some, const int lower, const int upper);
void filter(vector<string>& container);
~Filter();
private:
int scan(string& s);
private:
char some_char;
int lower_limit;
int upper_limit;
};
首先引入STL的string和vector,因为要把待过滤的字符串放到容器中,然后迭代容器,对每个字符串进行过滤。
公有行为:
有一个默认的构造函数,没有任何参数;另一个具有参数的构造函数,参数分别是指定字符、区间下界、区间上界;filter函数对传入的vector容器执行过滤操作;最后一个是析构函数。
私有行为:
scan函数是私有的,只能被该类使用,实现对一个字符串进行扫描,统计指定字符出现的次数。每次从vector中迭代出一个字符串,就调用scan函数统计一次。
私有成员:
也就是该类的私有数据,some_char是指定的字符,lower_limit是区间下界,upper_limit是区间上界。
实现Filter类,如下所示:
Filter::Filter() : lower_limit(0), upper_limit(0) {
}
Filter::Filter(const char some, const int lower, const int upper) : some_char(some), lower_limit(lower), upper_limit(upper) {
}
void Filter::filter(vector<string>& container) {
vector<string> v;
vector<string>::iterator it = container.begin();
while(it!=container.end()) {
int count = scan(*it);
if(count>=lower_limit && count<=upper_limit) {
v.push_back(*it);
}
it++;
}
container = v;
}
int Filter::scan(string& s) {
string::size_type size = s.size();
int count = 0;
string::size_type pos = s.find(some_char, 0);
while(pos != string::npos) {
count++;
if(pos == size-1) {
break;
}
else {
pos = s.find(some_char, pos+1);
}
}
return count;
}
Filter::~Filter() {
}
测试主函数如下所示:
int main() {
vector<string> vtr;
vtr.push_back("123455897328455545"); // 5:6
vtr.push_back("55555555555555555"); // 5:17
vtr.push_back("000998766532245"); // 5:2
vtr.push_back("1234998989893422"); // 5:0
vtr.push_back("0000055005500000"); // 5:4
vtr.push_back("888888436455532554"); // 5:5
cout<<vtr.size()<<endl;
char some = '5';
int lower = 5;
int upper = 12;
Filter *pfilter = new Filter(some, lower, upper);
pfilter->filter(vtr);
cout<<vtr.size()<<endl;
vector<string>::iterator it;
for(it=vtr.begin(); it!=vtr.end(); it++) {
cout<<*it<<endl;
}
delete pfilter;
return 0;
}
在容器中放入6个数字字符串,统计每个字符串出现字符'5'的个数,预期结果是,过滤掉5的个数不在区间[5, 12]的字符串,最后应该只有2个满足区间要求。
测试结果:
[root@bogon class]# g++ -o class class.cpp
[root@bogon class]# ./class
6
2
123455897328455545
888888436455532554
最后,看一下C++中实例化一个类的方法。
例如,对上面的Filter,我可以实例化该类,使用下面的方式:
char some = '5';
int lower = 5;
int upper = 12;
Filter ftr(some, lower, upper);
此时,实例化了一个类对象,可以通过引用filter来执行过滤行为:
vector<string> vtr;
……
ftr.filter(vtr);
还可以使用new关键字来实现:
char some = '5';
int lower = 5;
int upper = 12;
Filter *pfilter = new Filter(some, lower, upper);
此时,在堆上对该类的实例进行了空间的分配,返回了该Filter类的实例的指针pfilter,当需要执行过滤行为的时候,使用“->”来实现:
pfilter->filter(vtr);
因为使用了new关键字在堆上分配内存,在对象使用完成之后,需要手动进行释放:
delete pfilter;
这是必须要做的,否则会出现内存泄露,造成不必要的隐患。