C++面向对象三大特性之一
静态多态:函数重载和运算符重载都属于静态多态,复用函数名
动态多态:派生类和虚函数实现
class Animal {
public:
//加上virtual就是虚函数了,地址晚绑定
virtual void speak() {
cout << "speaking" << endl;
}
};
//加上virtual之后的继承叫虚继承,此时称Animal为虚基类
class Cat:public Animal {
public:
void speak() {
cout << "miao" << endl;
}
};
//地址早绑定,所以这里的cat传进去都会调用animal的speak方法
void dospeak(Animal &animal) {
animal.speak();
}
void test01() {
Cat cat;
dospeak(cat);//Animal &animal=cat,c++允许父类和子类的类型转换(不用强转)
}
父类的指针或引用指向子类对象
如:
void dospeak(Animal &animal) {
animal.speak();
}
Cat cat;
dospeak(cat);//Animal &animal=cat
virtual修饰的成员会在类内存放一个vfptr(虚函数指针),4字节大小
当子类继承父类时,同时也会继承父类的虚函数指针(也就同时继承了虚函数表vftable)
当子类重写父类虚函数时,vftable中的内容会被替换成子类的虚函数地址
class Calculator {
public:
Calculator(int a,int b) {
m_a = a;
m_b = b;
}
int getResult(string op) {
if (op == "+") {
return m_a + m_b;
}
if (op == "-") {
return m_a - m_b;
}
if (op == "*") {
return m_a * m_b;
}
if (op == "/") {
return m_a / m_b;
}
}
int m_a;
int m_b;
};
void test01() {
Calculator cal(10, 20);
string op = "/";
int result=cal.getResult(op);
cout << "result: " << result << endl;
}
普通的方法,如果想扩展新功能,需要修改源码
//实现计算器的基类
class Calculator {
public:
virtual int getResult() {
return 0;
}
int m_a;
int m_b;
};
//加法计算器
class addCal:public Calculator {
public:
//重写虚函数
int getResult() {
return m_a + m_b;
}
};
//减法计算器
class downCal :public Calculator {
public:
//重写虚函数
int getResult() {
return m_a - m_b;
}
};
//乘法计算器
class mulCal :public Calculator {
public:
//重写虚函数
int getResult() {
return m_a * m_b;
}
};
//除法计算器
class divCal :public Calculator {
public:
//重写虚函数
int getResult() {
return m_a / m_b;
}
};
void test01() {
//创建父类指针指向子类对象
//Calculator* cal = new addCal;
Calculator* cal = new divCal;
cal->m_a = 10;
cal->m_b = 10;
int result = cal->getResult();
cout << "result: " << result << endl;
delete cal;//记得销毁堆区数据
}
父类中的虚函数从来没想要调用,可以改成纯虚函数
//不需要定义函数体,直接=0,就是纯虚函数了
virtual int getResult() = 0;
只要包含了纯虚函数的类,就叫抽象类
抽象类不可实例化!!!
子类必须重写父类的纯虚函数,否则也视为抽象类,不可实例化!!!
//饮品基类
class makeDrink {
public:
//煮水
void boil() {
cout << "煮水ing..." << endl;
}
//冲泡
virtual void make() = 0;
//倒杯
void pool() {
cout << "倒杯ing..." << endl;
}
//辅料
virtual void addition() = 0;
void proceed() {
boil();
make();
pool();
addition();
}
};
class makeCoffe:public makeDrink {
public:
//冲泡
virtual void make() {
cout << "冲泡咖啡ing" << endl;
}
//辅料
virtual void addition() {
cout << "加入方糖、牛奶ing" << endl;
}
};
class makeTea:public makeDrink {
public:
//冲泡
virtual void make() {
cout << "冲泡茶叶ing" << endl;
}
//辅料
virtual void addition() {
cout << "加入柠檬ing" << endl;
}
};
void test01() {
makeDrink* maked=new makeCoffe;
maked->proceed();
makeDrink* maked1 = new makeTea;
maked1->proceed();
delete maked;
delete maked1;
}
多态在使用时,如果子类中有属性开辟在堆区,那么父类指针在释放时无法调用到子类的析构函数
将父类中的析构函数改为虚析构或纯虚析构
虚析构和纯虚析构共性:
虚析构和纯虚析构的区别:
纯虚析构的是抽象类,不可实例化
class Animal {
public:
Animal() {
cout << "父类构造" << endl;
}
virtual void speak() = 0;
利用虚析构可以解决父类指针释放子类对象时不干净的问题
//virtual ~Animal() {
// cout << "父类析构" << endl;
//}
//纯虚析构
virtual ~Animal() = 0;//注意,纯虚析构需要具体实现!否则会报错
};
Animal::~Animal() {
}
class Cat:public Animal {
public:
Cat(string name) {
cout << "子类构造" << endl;
m_name = name;
}
~Cat() {
cout << "子类析构" << endl;
}
void speak() {
cout << m_name << " miao" << endl;
}
string m_name;
};
void test01() {
Animal* cat1 = new Cat("Tom");//父类指针在析构的时候,不会调用子类中的析构函数,导致子类如果有堆区的数据,会出现内存的泄露
cat1->speak();
delete cat1;
}
不管是虚析构还是纯虚析构都需要代码实现,否则会报错
class CPU {
public:
virtual void calcu() = 0;
};
class VideoCard {
public:
virtual void display() = 0;
};
class Memo {
public:
virtual void storage() = 0;
};
class IntelCPU :public CPU{
public:
IntelCPU() {
cout << "using IntelCPU" << endl;
}
void calcu() {
cout << "IntelCPU正在计算" << endl;
}
};
class IntelVideoCard :public VideoCard {
public:
IntelVideoCard() {
cout << "using IntelVideoCard" << endl;
}
void display() {
cout << "IntelVideoCard正在显示" << endl;
}
};
class NvidiaVideoCard :public VideoCard {
public:
NvidiaVideoCard() {
cout << "using NvidiaVideoCard" << endl;
}
void display() {
cout << "NvidiaVideoCard正在显示" << endl;
}
};
class SamsungMemo:public Memo {
public:
SamsungMemo() {
cout << "using SamsungMemo" << endl;
}
void storage() {
cout << "SamsungMemo正在储存" << endl;
}
};
class Computer {
public:
Computer(CPU* cpu,VideoCard* videocard,Memo* memo) {
m_cpu = cpu;
m_videocard = videocard;
m_memo = memo;
}
void processing() {
m_cpu->calcu();
m_videocard->display();
m_memo->storage();
}
~Computer() {
if (m_cpu != NULL) {
delete m_cpu;
m_cpu = NULL;
}
if (m_videocard != NULL) {
delete m_videocard;
m_videocard = NULL;
}
if (m_memo != NULL) {
delete m_memo;
m_memo = NULL;
}
}
private:
CPU* m_cpu;
VideoCard* m_videocard;
Memo* m_memo;
};
void test01() {
CPU* intelcpu = new IntelCPU;
VideoCard* intelvc = new IntelVideoCard;
Memo* sammemo = new SamsungMemo;
Computer pc1(intelcpu,intelvc,sammemo);//这里需要传入指向子类对象的父类指针
pc1.processing();
delete pc1;
}
int main() {
test01();
system("pause");
return 0;
}
class Computer {
public:
Computer(CPU* cpu,VideoCard* videocard,Memo* memo) {//如果构造函数里传入的是指针,就可以随时改变该指针指向的对象
m_cpu = cpu;
m_videocard = videocard;
m_memo = memo;
}
void processing() {
m_cpu->calcu();
m_videocard->display();
m_memo->storage();
}
private:
CPU* m_cpu;
VideoCard* m_videocard;
Memo* m_memo;
};
Computer pc1(intelcpu,intelvc,sammemo);//这里需要传入指向子类对象的父类指针
头文件
ios::in | 为读文件打开文件 |
---|---|
ios::out | 为写文件打开文件 |
ios::ate | 初始位置:文件尾 |
ios::app | 追加方式写文件 |
ios::trunc | 如果文件存在先删除,再创建 |
ios::binary | 二进制方式 |
打开方式可以**用|**配合使用
if(!ifs.is_open()){
//文件未打开
return;
}
int main() {
//1.引入头文件
//2.创建ifstream对象
ifstream ifs;
//3.打开文件
ifs.open("test.txt", ios::in);
if (!ifs.is_open()) {
cout << "打开失败" << endl;
return -1;
}
//4.读文件
第一种读文件
//char buf[1024] = { 0 };
//while (ifs >> buf) {
// cout << buf << endl;
//}
第二种读文件
//char buf[1024] = { 0 };
//while (ifs.getline(buf, sizeof(buf))) {
// cout << buf << endl;
//}
//第三种读文件
string buf;
while (getline(ifs, buf)) {
cout << buf << endl;
}
//5.关闭文件
ifs.close();
system("pause");
return 0;
}
class Person {
public:
char m_name[64];
int m_age;
};
int main() {
二进制写文件
//ofstream ofs;
//ofs.open("person.txt", ios::out|ios::binary);
//Person p1 = { "zhangsan",20 };
//ofs.write((const char* )&p1,sizeof(Person));
//ofs.close();
//二进制读文件
ifstream ifs;
ifs.open("person.txt", ios::in | ios::binary);
if (!ifs.is_open()) {
return -1;
}
Person p2;
ifs.read((char*)&p2,sizeof(Person));
cout << p2.m_name << " " << p2.m_age << endl;
system("pause");
return 0;
}