使用C接口我们必须遵守它的一些隐藏约定,如果不遵守这些约定的话在程序运行时可能会出现奇怪的情况而导致失败,我们可以使用C++的数据抽象概念对C接口进行改进;对于C++而言,如果对某个类对象的所有单个方法的调用都会让对象置于一种合理的状态,那么对象的状态就能始终保持合理
这个例子针对C语言检查文件系统目录的一个例程集 传统条件下的C语言实现
#include <stdio.h>
#include <dirent.h>
int main()
{
DIR *dp = opendir(".");
struct dirent *d;
while(d = readdir(dp))
{
printf("%s\n", d->d_name);
}
closedir(dp);
return 0;
}
这种实现将导致主要的几个问题如下,第一个打开的目录无效 或者readdir(dp)函数传入的指针无效 这将导致程序出现错误。这些错误为大家所常见。还有一种错误,将导致读取的值为无效的值。
DIR *dp1 = opendir("..//.");
DIR *dp2 = dp1;
struct dirent *d1,*d2;
d1=readdir(dp1);
d2=readdir(dp2);
printf("%s\n",d1->d_name);
printf("%s\n",d2->d_name);
closedir(dp1);
为什么会出现这样无效值的出现呢,很简单,因为我们两个对象是对同一个内存块进行操作,这回影响同一个结构体的参数的变化。那么我们应该如何用C++技术来减少这种错误来发生呢,我们设计了下面两个类,来实现目标功能。
class Dir
{
public:
Dir(const char* file):dp(opendir(file))//调用底层函数
{}
~Dir()
{
if(dp)//dp如果打开失败 那就没有必要析构了,就是这样简单
closedir(dp);
}
void seek(Dir_offset pos)//
{
if(dp)
seekdir(dp, pos);//// operator long() { return l; }涉及到类型强制转换
}
Dir_offset tell() const
{
if(dp)
return telldir(dp);//调用构造函数
return -1;//这里也会调用构造函数
}
int read(dirent& d)//传出参数 这个参数比较重要
{
if(dp)
{
dirent* r = readdir(dp);
if(r)
{
d = *r;
return 1;
}
}
return 0;
}
private:
DIR* dp;
Dir(const Dir&);
Dir& operator=(const Dir&);
};
/*
正如上文所述的,我们只是对原有的程序进行的适当的封装,也就是说我们的程序依旧依赖于DIR *dir指针, 如果对象复制, 我们操作的还是同一个内存块,也就是说对象之间将产生相互影响,这将导致错误,因而,这里讲对象的复制操作,都进行了禁止。
*/
class Dir_offset
{
public:
friend class Dir;
long l;
Dir_offset(long n = 0) { l = n; }//这是偏移量的设置,默认为0
operator long() { return l; }//这个是将对象强制转换成 long类型 operator的用法
};
测试如下:
int main()
{
/*
测试程序
*/
Dir d(".");
dirent dd;
while(d.read(dd))
{
cout << dd.d_name <<endl;
}
//测试对象的强制转换
// Dir_offset d = (Dir_offset)-1;
return 0;
}