1.面向对象编程的特性
程序由类(class)构成,基本特征为封装性、继承性和多态性.
2.c++文件的使用
1.打开文件
一般使用的头文件
fstream类都有一个函数
😁为了写的out与为了读的in 是相对于程序而言的😁
void open(const char* filename,int mode,int access);
fstream file1;
file1.open("c:config.sys",ios::binary|ios::in,0);
fstream file1("c:config.sys"); //使用fstream自身的构造函数
特别提出的是,fstream有两个子类:ifstream(input file stream)和ofstream(outpu file stream),ifstream默认以输入方式打开文件,而ofstream默认以输出方式打开文件
ifstream file2("c:pdos.def");//以输入方式打开文件
ofstream file3("c:x.123");//以输出方式打开文件
mode:
ios::app: 以追加的方式打开文件
ios::ate: 文件打开后定位到文件尾,ios:app就包含有此属性
ios::binary: 以二进制方式打开文件,缺省的方式是文本方式。两种方式的区别见前文
ios::in: 文件以输入方式打开 //为了读而打开的文件
ios::out: 文件以输出方式打开 //为了写而打开的文件
ios::nocreate: 不建立文件,所以文件不存在时打开失败
ios::noreplace:不覆盖文件,所以打开文件时如果文件存在失败
ios::trunc: 如果文件存在,把文件长度设为0
可以用“或”把以上属性连接起来,如ios::out|ios::binary
mode://一般不用填
0:普通文件,打开访问
1:只读文件
2:隐含文件
4:系统文件
二、关闭文件
file.close()
三、读写文件
1、文本文件的读写
简单操作
file2<<"I Love You";//向文件写入字符串"I Love You"
int i;
file1>>i;//从文件输入一个整数值。
还可以指定格式
- 操纵符 功能 输入/输出
dec 格式化为十进制数值数据 输入和输出
endl 输出一个换行符并刷新此流 输出
ends 输出一个空字符 输出
hex 格式化为十六进制数值数据 输入和输出
oct 格式化为八进制数值数据 输入和输出
setpxecision(int p) 设置浮点数的精度位数 输出
例子
file1<<hex<<123;//十六进制
file1<<setpxecision(5)<<3.1415926;//五位精度
②使用getline()
// reading a text file
#include <iostream>
#include <fstream>
#include <string>
using namespace std;
int main () {
string line;
ifstream myfile ("example.txt");
if (myfile.is_open())
{
while ( getline (myfile,line) )//like cin
{
cout << line << '\n';
}
myfile.close();
}
else cout << "Unable to open file";
return 0;
}
2.二进制文件读写
①put()
put()函数向流写入一个字符,其原型是ofstream &put(char ch),使用也比较简单,如file1.put(‘c’);就是向流写一个字符’c’。
②get()
get()函数比较灵活,有3种常用的重载形式:
一种就是和put()对应的形式:ifstream &get(char &ch);功能是从流中读取一个字符,结果保存在引用ch中,如果到文件尾,返回空字符。如file2.get(x);表示从文件中读取一个字符,并把读取的字符保存在x中。
另一种重载形式的原型是: int get();这种形式是从流中返回一个字符,如果到达文件尾,返回EOF,如x=file2.get();和上例功能是一样的。
还 有一种形式的原型是:*ifstream &get(char buf,int num,char delim=‘n’);这种形式把字符读入由 buf 指向的数组,直到读入了 num 个字符或遇到了由 delim 指定的字符,如果没使用 delim 这个参数,将使用缺省值换行符’n’。例如:
file2.get(str1,127,‘A’);//从文件中读取字符到字符串str1,当遇到字符’A’或读取了127个字符时终止。
因为二进制不需要含格式化 因而不用cin cout与getline()
③块读入读出
unsigned char str1[]="I Love You";
int n[5];
ifstream in("xxx.xxx");
ofstream out("yyy.yyy");
out.write(str1,strlen(str1));//把字符串str1全部写到yyy.yyy中
in.read((unsigned char*)n,sizeof(n));//从xxx.xxx中读取指定个整数,注意类型转换
in.close();out.close();
四、检测EOF
if(in.eof())ShowMessage("已经到达文件尾!");
五、文件定位
istream &seekg(streamoff offset,seek_dir origin); //读操作
ostream &seekp(streamoff offset,seek_dir origin);//写操作
offset是偏移大小
seek_dir:
ios::beg: 文件开头
ios::cur: 文件当前位置
ios::end: 文件结尾
获取文件大小的方法:
in.seekg(0, in.end);
int length = in.tellg();//length就是文件大小
in.seekg(0, in.beg);
之后通过
if (in.is_open()) {
cout << "Now reading..." << endl;
in.read(temp, length); //全部就可以读取啦
}
六.判断文件是否打开成功
c++文件打开失败不会抛出异常,所以不能使用try catch(exception)
正确的方法可以直接利用fstream重载了!操作符:
ifstream fin("filename");
if (!fin)
{
cout << "fail to open the file" <<endl;
return -1;//或者抛出异常。
}
else
{
cout << "open the file successfully" << endl;
}
或者利用file.is_open()函数
二.继承
CSDN 隐藏与覆盖
1.运算符重载,在重载之后 cout << A + B return的其实是 代表的
cout << A + B这个整体
2. *可以通过基类指针访问派生类方法(强制转换和虚函数),不存在通过派生类指针调用基类成员函数的方法(即便是强制转换)
\
基类指针可以指向派生类对象,但是派生类指针不能指向基类对象
thanks for 详解指针关系
函数隐藏和函数覆盖只会发生在基类和派生类之间。
函数隐藏是指派生类中函数与基类中的函数同名,但是这个函数在基类中并没有被定义为虚函数,这种情况就是函数的隐藏。
所谓隐藏是指使用常规的调用方法,派生类对象访问这个函数时,会优先访问派生类中的这个函数,基类中的这个函数对派生类对象来说是隐藏起来的。 但是隐藏并不意味这不存在或完全不可访问。通过 b->Base::func()访问基类中被隐藏的函数。
**函数覆盖(多态现象)**特指由基类中定义的虚函数引发的一种多态现象。在某基类中声明为 virtual 并在一个或多个派生类中被重新定义的成员函数,用法格式为:virtual 函数返回类型 函数名(参数表) {函数体};实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数。
函数覆盖的条件:
1: 基类中的成员函数被virtual关键字声明为虚函数;
2:派生类中该函数必须和基类中函数的名称、参数类型和个数等完全一致;
3:将派生类的对象赋给基类指针或者引用,实现多态。
函数覆盖(多态)实现了一种基类访问(不同)派生类的方法。我们把它称为基类的逆袭。
具体代码参见上方链接
C++primer
继承
(当通过指针或者引用调用虚函数时该调用会被动态绑定)
根据引用或者指针所绑定的对像不同,该调用可能执行基类的版本也可能指向派生类的版本
double print_total(ostream &os, const Base &item, int n)
{
item 可以传入 Base类 或者 派生类 相当于对item动态绑定了不同的对象
对于定义在Base 中的虚函数 如果派生类有实现的话,
根据传入的是Base对象还是派生类对像执行不同的函数
因而会实现动态绑定。
}
任何构造函数之外的非静态函数都可以是虚函数。
派生类
1.可以同时继承多了基类,中间用逗号隔开
2.派生类在构造函数中最好调用基类的构造函数来初始化基类的对象、
继承与静态成员
静态成员函数在基类中如果是private的,则派生类无权访问它。假设某静态函数可以访问,则我们既可以通过基类对象访问也可以通过派生类对象访问
class Base
{
public:
static void statement();
};
class Derived : public Base
{
void f(const Derived&);
};
void Derived ::f(const Derived&obj)
{
Base ::stamen();
Derived ::statment();
obj.statmen();
statmen();//这里由于是在Derived 的作用域内所以可以通过this访问
}
派生类的声明
声明中包含类名但是不包含它的派生类列表!!!
基类的类
一个类被用作基类之前必须实现定义。
防止继承发生
class 类名 final{};
虚函数
如果派生类要覆盖基类得虚函数则必须函数名与参数列表完全相同
在基类成员函数或者友元中的代码才需要使用作用域运算符来回避虚函数的机制。 baseP->Quote::net(42) net一定是Quote中的函数了。
如果一个类不想被实现出对象,那么可以将其中的函数定义成纯虚函数
virtual 函数 = 0
虚函数必须要有定义,纯虚函数一般没有定义。
访问权限
友元不具有继承特性
using
1.可以通过using语句改变成员的可访问性
class Derived :private Base{
public:
using Base::size;
protected:
using Base::n;
}
本来是私有的继承对于Base类里的元素 Derived的对象应该是不能访问的,但是使用了using之后就可以访问了
注意using 也只是能访问Base的public 与 private
如果using声明语句位于protected部分,则该名字对于成员,友元和派生类时可访问的。
2.为了防止派生类将基类的全部重载的函数覆盖了可以使用using 函数名(不需要参数列表)