实用C++学习笔记7

42 多态性与虚函数

https://www.cctry.com/thread-290046-1-1.html
多态:向不同的对象发送同一个消息,不同的对象在接收时会产生不同的行为。

例如:成员函数的重载

使用虚函数实现多态:

使用基类的指针,指向派生类的对象,调用虚函数的时候,最后调用的是派生类的函数!

int main()
{
    CZhongStudent stud_zhong;
    stud_zhong.shangke();  //调用的是CZhongStudent的函数

    CStudent* pStud; 
    pStud = &stud_zhong;  //父类的指针指向子类的对象
    pStud->shangke();  //调用的是CStudent的函数
    //所以就是,用类的指针指向子类的对象,用父类的指针调用shangke(),调用的也还是父类的shangke()
    return 0;
}

如果想要对象是谁就调用谁的函数(即:比如上面的情况,父类对象pStud引用子类对象stud_zhong,所以实际上对象就是子类对象stud_zhong,那么调用函数的时候想调用的是子类CZhongStudent的shangke()),默认是不行的,但是可以把shangke()这个函数声明成虚函数

在函数声明前加virtual(要在父类中加,在子类中不用加)

虚函数的注意事项:

①、virtual 只能用来声明类的成员函数,把它作为虚函数,而不能将类作用域外的普通函数声明成虚函数。因为虚函数的作用是允许在派生类中对基类的虚函数重新定义。显然,他只能用于类的继承层次结构中;
②、一个类中的某个函数被声明成虚函数之后,同一类中就不能再定义一个非virtual的参数和返回值类型都相同的成员函数了。

什么情况下使用虚函数:

一般情况下是某个函数所在的类可能会作为父类/基类,而且该函数有可能会被派生类重写,并被派生类使用,那么这个时候就可以考虑将该函数声明为virtual 虚函数。否则就不用!因为声明成虚函数之后是有开销的,所以不要随随便便的想声明成虚函数就声明。

小作业:
创建一个狗的类 CDog,包含 wangwang 这个虚函数,之后从 CDog 分别派生2-3个子类,比如:有金毛、吉娃娃、藏獒 等。分别实现每个子类的 wangwang 方法,之后试着调用该方法,充分理解虚函数的特性!

#include <iostream>
#include <string>
using namespace std;

class CDog
{
public:
	virtual void wangwang()
	{
		cout << "CDog 汪!" << endl;
	}
};

class CJinmaoDog :public CDog
{
public:
	void wangwang()
	{
		cout << "CJinmaoDog 汪!" << endl;
	}
};

class CJiwawaDog :public CDog
{
public:
	void wangwang()
	{
		cout << "CJiwawaDog 汪!" << endl;
	}
};

class CZangaoDog :public CDog
{
public:
	void wangwang()
	{
		cout << "CZangaoDog 汪!" << endl;
	}
};

int main()
{
	CDog *p_dog;
	CJinmaoDog jinmao;
	CJiwawaDog jiwawa;
	CZangaoDog zangao;

	p_dog = &jinmao;
	p_dog->wangwang();

	p_dog = &jiwawa;
	p_dog->wangwang();

	p_dog = &zangao;
	p_dog->wangwang();
	return 0;
}

在这里插入图片描述

43 文件IO操作之打开与关闭

#include <iostream>
#include <fstream>
using namespace std;



int main()
{
	short var = 10000;

	ofstream fs1;  //输出到文件
	fs1.open("d:\\1.txt");
	fs1 << var << endl;
	fs1.close();

	ifstream fs2;
	fs2.open("d:\\1.txt");  //从文件输入
	var = 0;
	fs2 >> var;
	cout << var << endl;

	//此时文件占7个字节,“10000”是5个,剩下两个是endl的,显示“10000 CR LF ”

	//下面是关于二进制的操作:
	fs1.open("d:\\1.txt");
	fs1.write((char*)&var, sizeof(short));
	fs1.close();
	fs2.open("d:\\1.txt");
	fs2.read((char*)&var, sizeof(short));
	cout << var << endl;
	//此时文件占2个字节, 显示为“ N”,因为本身short占2字节
	//所以就是文本文件易读,但占空间多,二进制文件占空间小,但看不懂。根据需要选择
	return 0;
}

C++中的文件操作类:

fstream(输入输出文件流):支持文件的输入与输出操作;
ifstream(输入文件流):支持从文件中输入操作;
ofstream(输出文件流):支持向文件写入的操作;

文件的打开操作:构造函数与open函数

ofstream fs("z:\\123.txt");
fs.open("z:\\123.txt");

这两种操作都是可以的。

实际上open函数有多个参数,第2个参数也很常用,表示打开文件的方式,取值有如下:
ios::in 为输入(读)而打开文件
ios::out 为输出(写)而打开文件
ios::ate 初始位置:文件尾
ios::app 所有输出附加在文件末尾
ios::trunc 如果文件已存在则先删除该文件
ios::binary 二进制方式

这些方式是能够进行组合使用的,以“或”运算(“|”)的方式,例如:

ofstream fs;  
fs.open("123.txt", ios::in|ios::out|ios::binary);

ios::in ios::out 如果不写,会默认存在:

ofstream fs1("123.txt", ios::out);
ifstream fs2("123.txt", ios::in);
fstream fs3("123.txt", ios::in|ios::out);

判断文件是否成功打开:

几种方法:
①、直接 if 判断 fs 对象;
②、用 is_open 方法判断;
③、用 good 方法判断;
④、用 fail 方法判断;

①②常用

if(!fs)
{
	cout << "open error" << endl;
}

if(!is_open)
{
	cout << "open error" << endl;
}

文件流的关闭:fs.close()

小作业:
使用 fstream 文件流来对文件进行读写操作:

#include <iostream>
#include <fstream>
using namespace std;



int main()
{
	short var = 10000;

	fstream fs; 
	fs.open("d:\\1.txt");
	fs << var <<endl;
	fs.close();

	fs.open("d:\\1.txt");  //一定要关了重新开,不然的话读不到文件里的数据,var输出会是200
	var = 200;
	fs >> var;
	fs.close();
	cout << var << endl;  //输出10000,证明是从文件里读到的
	return 0;
}

44 文件IO操作之读写

文件的写操作:
写操作对应的有:<<、put、write 等
①、写文本类型/ASCII码类型的可见字符串:<<put

	ofstream fs;
	fs.open("d:\\1.txt");
	if (!fs) return 0;

	fs << 2000 << endl;
	fs << 2.15 << endl;
	fs << "hello" << endl;

	fs.put('Y');  //只能写入字符

②、二进制类型写文件:write

	int var = 12345;
	fs.write((const char*)&var,sizeof(var));  //第一个参数是开始的地址,第二个参数是长度
	//这样子写入,显示的是乱码
//也可以显示明文的:
	char s[] = "你好";
	fs.write(s, sizeof(s));

常用的是<<和write()

文件的读操作:

①、读文本类型/ASCII码类型的文件:>>、get、getline

	ifstream fs_read;
	fs_read.open("d:\\1.txt");

	int a = 0;
	fs_read >> a;  //把文本文件里的第1个值2000读到a中
	float f_var = 0;
	fs_read >> f_var;  //把文本文件里的第2个值2.15读到f_var中
	char s_var[100] = { 0 };
	fs_read >> s_var;  //把文本文件里的第3个值hello读到f_var中
	char ch = fs_read.get(); //从文本文件只读一个字符,把值‘\n’ 读到ch中
	ch = fs_read.get();  //从文本文件只读一个字符,把值‘Y’ 读到ch中

getline 函数:从文件中读取一行数据(所谓的一行就是有换行符 \n,或者达到 getline 的缓冲区大小,或者读到文件末尾。)

ifstream fs_read;
	fs_read.open("d:\\1.txt");
	char s2[100];
	for (int i = 0; i < 4; i++)
	{
		memset(s2, 0, 100);
		fs_read.getline(s2, 100);
		cout << s2 << endl;
	}

②、读取二进制文件类型:read

ofstream fs;
	fs.open("d:\\1.txt");
	if (!fs) return 0;

	int var = 12345;
	fs.write((const char*)&var, sizeof(var));  //第一个参数是开始的地址,第二个参数是长度
	
	char s[] = "你好";
	fs.write(s, sizeof(s));

	fs.close();

	ifstream fs_read;
	fs_read.open("d:\\1.txt");

	int var2 = 0;
	fs_read.read((char*)&var2, sizeof(int));
	cout << var2 << endl;

	char s2[100] = { 0 };
	fs_read.read(s2, 100);
	cout << s2 << endl;
	fs_read.close();

小作业:
如何判断读写文件的操作/函数是否成功了呢?以及如何判断是否读到文件末尾了呢?

判断文件是否为空时使用peek函数,若peek返回EOF则文件为空;读取非char型时,使用peek判断文件尾将不再适用
(第一问不会。。)

猜你喜欢

转载自blog.csdn.net/weixin_45550460/article/details/106452846