超女选秀的例子咱们玩了好久,为了学习的须要,暂时离开美眉们,我将采用实际项目开发的例子来说解类的更多知识。python
在C语言基础知识中已学习过文件操做,在实际开发中,为了提升效率,我会把文件操做封装成一个类,类的声明以下:linux
// 文件操做类声明 class CFile { private: FILE *m_fp; // 文件指针 bool m_bEnBuffer; // 是否启用缓冲区,true-启用;false-不启用 public: CFile(); // 类的构造函数 CFile(bool bEnBuffer); // 类的构造函数 ~CFile(); // 类的析构函数 void EnBuffer(bool bEnBuffer=true); // 启、禁用缓冲区 // 打开文件,参数与fopen相同,打开成功true,失败返回false bool Open(const char *filename,const char *openmode); // 调用fprintf向文件写入数据 void Fprintf(const char *fmt, ... ); // 调用fgets从文件中读取一行 bool Fgets(char *strBuffer,const int ReadSize); // 关闭文件指针 void Close(); };
C++经过 public、protected、private三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。所谓访问权限,就是类外面的代码访问该类中成员权限。程序员
在类的内部,即类的成员函数中,不管成员被声明为 public、protected 仍是private,都是能够互相访问的,没有访问权限的限制。ide
在类的外部(定义类的代码以外),只能经过对象访问public的成员,不能访问 private、protected属性的成员。函数
本节重点介绍 public 和 private,protected 将在之后介绍。学习
private 后面的成员都是私有的,如m_fp和m_bEnBuffer,直到有 public出现才会变成共有的;public 以后再无其余限定符,因此 public后面的成员都是共有的。测试
private关键字的做用在于更好地隐藏类的内部实现,该向外暴露的接口(能经过对象访问的成员)都声明为public,不但愿外部知道、或者只在类内部使用的、或者对外部没有影响的成员,都建议声明为private。this
声明为 private 的成员和声明为 public 的成员的次序任意,既能够先出现 private部分,也能够先出现 public 部分。若是既不写 private 也不写 public,就默认为private。.net
在一个类体中,private 和 public能够分别出现屡次。每一个部分的有效范围到出现另外一个访问限定符或类体结束时(最后一个右花括号)为止。设计
您可能会说,将成员变量所有设置为 public 省事,确实,这样作 99.9%的状况下都不是一种错误,我也不认为这样作有什么不妥;可是,将成员变量设置为private 是一种软件设计规范,尤为是在大中型项目中,仍是请你们尽可能遵照这一原则。
成员变量大都以m_开头,这是约定成俗的写法,不是语法规定的内容。以m_开头既能够一眼看出这是成员变量,又能够和成员函数中的参数名字区分开。
例如成员函数EnBuffer的函数体以下:
// 启、禁用缓冲区 void CFile::EnBuffer(bool bEnBuffer) { m_bEnBuffer=bEnBuffer; }
在CFile类的声明中,有一些特殊的成员函数CFile(),它就是构造函数(constructor)。
CFile(); // 类的构造函数 CFile(bool bEnBuffer); // 类的构造函数
构造函数的名字和类名相同,没有返回值,不能被显式的调用,而是在建立对象时自动执行。
构造函数具有如下特色:
1)构造函数必须是 public 属性。
2)构造函数没有返回值,由于没有变量来接收返回值,即便有也毫无用处,不论是声明仍是定义,函数名前面都不能出现返回值类型,即便是void 也不容许。
3)构造函数能够有参数,容许重载。一个类能够有多个重载的构造函数,建立对象时根据传递的参数来判断调用哪个构造函数。
4)构造函数在实际开发中会大量使用,它每每用来作一些初始化工做,对成员变量进行初始化等,注意,不能用memset对整下类进行初始化。
示例
CFile::CFile() // 类的构造函数 { m_fp=0; m_bEnBuffer=true; } CFile::CFile(bool bEnBuffer) // 类的构造函数 { m_fp=0; m_bEnBuffer=bEnBuffer; }
在CFile类的声明中,还有一个特殊的成员函数\~CFile(),它就是析构函数(destructor)。
~CFile(); // 类的析构函数
析构函数的名字在类的名字前加\~,没有返回值,但能够被显式的调用,在对象销毁时自动执行,用于进行清理工做,例如释放分配的内存、关闭打开的文件等,这个用途很是重要,能够防止程序员犯错。
析构函数具有如下特色:
1)构造函数必须是 public 属性的。
2)构造函数没有返回值,由于没有变量来接收返回值,即便有也毫无用处,不论是声明仍是定义,函数名前面都不能出现返回值类型,即便是void 也不容许。
3)析构函数不容许重载的。一个类只能有一个析构函数。
CFile::~CFile() // 类的析构函数 { Close(); // 调用Close释放资源 }
不少人说C/C++程序很烦锁,python程序很优雅,说这话人的很荒谬,那是由于他C/C++并不了解,只要咱们愿意,能够写出和python同样优雅简洁的代码,在book210.cpp中,main函数的代码极为精简。
示例(book210.cpp)
/* * 程序名:book210.cpp,此程序演示用C++类的更多知识。 * 做者:C语言技术网(www.freecplus.net) 日期:20190525 */ #include <stdio.h> #include <string.h> #include <stdarg.h> // 文件操做类声明 class CFile { private: FILE *m_fp; // 文件指针 bool m_bEnBuffer; // 是否启用缓冲区,true-启用;false-不启用 public: CFile(); // 类的构造函数 CFile(bool bEnBuffer); // 类的构造函数 ~CFile(); // 类的析构函数 void EnBuffer(bool bEnBuffer=true); // 启、禁用缓冲区 // 打开文件,参数与fopen相同,打开成功true,失败返回false bool Open(const char *filename,const char *openmode); // 调用fprintf向文件写入数据 void Fprintf(const char *fmt,... ); // 调用fgets从文件中读取一行 bool Fgets(char *strBuffer,const int ReadSize); // 关闭文件指针 void Close(); }; int main(int argc,char *argv[]) { if (argc !=2) { printf("请输入待打开的文件名。\n"); return -1; } CFile File; if (File.Open(argv[1],"r")==false) { printf("File.Open(%s)失败。\n",argv[1]); return -1; } char strLine[301]; while (true) { // 从文件中读取每一行 if (File.Fgets(strLine,300)==false) break; printf("%s",strLine); // 把从文件中读到的内容显示到屏幕 } } CFile::CFile() // 类的构造函数 { m_fp=0; m_bEnBuffer=true; } CFile::CFile(bool bEnBuffer) // 类的构造函数 { m_fp=0; m_bEnBuffer=bEnBuffer; } // 关闭文件指针 void CFile::Close() { if (m_fp!=0) fclose(m_fp); // 关闭文件指针 m_fp=0; } CFile::~CFile() // 类的析构函数 { Close(); // 调用Close释放资源 } // 启、禁用缓冲区 void CFile::EnBuffer(bool bEnBuffer) { m_bEnBuffer=bEnBuffer; } // 打开文件,参数与fopen相同,打开成功true,失败返回false bool CFile::Open(const char *filename,const char *openmode) { Close(); // 打开新的文件以前,若是已经打开了文件,关闭它。 if ( (m_fp=fopen(filename,openmode)) == 0 ) return false; return true; } // 调用fprintf向文件写入数据 void CFile::Fprintf(const char *fmt,...) { if ( m_fp == 0 ) return; va_list ap; va_start(arg,ap); vfprintf(m_fp,fmt,ap); va_end(ap); if ( m_bEnBuffer == false ) fflush(m_fp); } // 调用fgets从文件中读取一行 bool CFile::Fgets(char *strBuffer,const int ReadSize) { if ( m_fp == 0 ) return false; memset(strBuffer,0,ReadSize); if (fgets(strBuffer,ReadSize,m_fp) == 0) return false; return true; }
book210运行的效果就是把文件的内容一行一行的显示出来,类型linux系统的cat命令。
关于类的其它知识,包括this指针、static静态成员、友元等内容,意义不大,我不介绍了,时间太宝贵,有太多重要的知识要学习,不必把时间浪费在这些不痛不痒又没什么实用价值的知识点上,你们之后有时间了再看也行。
咱们已经介绍过printf、fprintf、sprintf、snprintf函数,它们是一组功能类似的函数,而且有一个共同点,就是函数的参数列表是能够变化的。
函数的声明以下:
int printf(const char *format, ...); // 格式化输出到屏幕 int fprintf(FILE *stream, const char *format, ...); // 格式化输出到文件 int sprintf(char *str, const char *format, ...); // 格式化输出到字符串 int snprintf(char *str, size_t size, const char *format, ...); // 格式化输出指定长度的内容到字符串
在实际开发中,咱们的自定义函数也会用到可变参数,实现相似上述函数的功能,例如CFile类的Fprintf成员函数。
C语言采用va_start宏、va_end宏和一系列函数来实现可变参数功能。
void CFile::Fprintf(const char *fmt,...) { if ( m_fp == 0 ) return; va_list ap; va_start(arg,ap); vfprintf(m_fp,fmt,ap); va_end(ap); if ( m_bEnBuffer == false ) fflush(m_fp); }
以CFile类的Fprintf成员函数为例。
void CFile::Fprintf(const char *fmt,...); // 可变参数自定义函数的声明方法
va_list指针、va_start宏、va_end宏用于分析参数,难以理解,你们会用就行,我不详细介绍。
va_list ap; va_start(ap,fmt); vfprintf(m_fp,fmt,ap); va_end(ap);
vfprintf函数把宏分析的结果输出到文件,还有一系列功能类似的函数,声明以下:
// 输出的屏幕 int vprintf(const char *format, va_list ap); // 输出到文件 int vfprintf(FILE *stream, const char *format, va_list ap); // 输出到字符串 int vsprintf(char *str, const char *format, va_list ap); // 输出到字符串,第二个参数指定了输出结果的长度,相似snprintf函数。 int vsnprintf(char *str, size_t size, const char *format, va_list ap);
1)编写示例程序,测试类的类成员的访问权限。
2)编写示例程序,测试类的构造函数和它的重载,采用gdb跟踪构造函数的执行过程。
3)编写示例程序,测试类的析构函数,采用gdb跟踪析构造的执行过程。
4)编写示例程序,实现printf、sprintf和snprintf函数的功能,函数的声明以下:
int myprintf(const char *format, ...); int mysprintf(const char *format, ...); int mysnprintf(const char *format, ...);
5)类定义包括成员变量和成员函数的声明以及成员函数的定义,在实际开发中,咱们一般将公共类的声明放在头文件中(如_public.h),成员函数的定义放在程序文件中(如_public.cpp),请按这种方式修改book210.cpp程序,增长_public.h和_public.cpp程序,修改makefile。
C语言技术网原创文章,转载请说明文章的来源、做者和原文的连接。
来源:C语言技术网(www.freecplus.net)
做者:码农有道
若是这篇文章对您有帮助,请点赞支持,或在您的博客中转发个人文章,谢谢!!!若是文章有错别字,或者内容有错误,或其余的建议和意见,请您留言指正,很是感谢!!!