C++ 类和对象

Animal:: ~Animal()
{
}

引言

 面向对象的三大特性:封装、继承、多态

 具有相同性质的对象抽象为类:

                                 

封装

1.1 定义

语法: class 类名 {访问权限:属性/行为 };

class Student
{
public:
	string m_name;
	int m_age;
};

                                        

访问:用“.”访问属性/行为 

	Student s1;                      //实例化一个对象
	cout << s1.m_age << endl;        //用“.”访问

 习惯

         1.(函数)在类内定义,类外初始化      

         2.用行为给属性赋值 (在外部通过公有方法访问私有成员,该方法(成员函数)称为这个类              的一个外部接口)   

#include <iostream>
#include <string>
using namespace std;
class Student
{
public:
	void func(string name, int age);  //类内定义
private:
	string m_name;
	int m_age;
};

void  Student::func(string name,int age)  //类外初始化 ;用行为给属性赋值
{
	m_name = name;
	m_age = age;
	cout << m_name << ":" << m_age << endl;
}

int main()
{
	Student s1;                     
	s1.func("小明",12);
	system("pause");
	return 0;
}

1.2 访问权限

public:公共权限,类内外均可访问        

protected:保护权限,子类可以访问,类内可以访问,类外不可访问

private:私有权限,子类也不可以访问,只有内类能访问

1.3 对象的初始化和清理

编译器会提供构造函数和析构函数的空实现

1.3.1构造函数

语法:  类名(){}

特点:①没有返回值 ②可以有参数,可以发生重载 ③创建对象时,自动调用,且只调用一次

1.3.2 析构函数

语法:  ~类名(){}

特点:①没有返回值 ②没有参数,因此不能发生重载 ③销毁前,自动调用,且只调用一次

class Person
{
public:
	Person()
	{
		cout << "调用构造函数" << endl;
	}
	~Person()
	{
		cout << "调用析构函数" << endl;
	}
};
void test1(void)
{
	Person p1;  //创建Person的对象p1时,自动调用Person类中的构造函数,输出“调用构造函数”
}
int main()
{
	cout << "主函数" << endl;
	test1();//执行这句时才会调用构造,执行完,调用析构
	system("pause");
	return 0;
}

1.3.3 构造函数的分类及调用

分类

    ①默认构造:Person(){}

    ②有参构造 :Person(int age){m_age=age;}

    ③拷贝构造:Person(const Person&p){m_age=p.age;}

       *拷贝构造 是用值传递的方式给函数传参

调用方式

    调用默认构造时,不要写()

    ①括号法 :Person p1;(调用默认构造)

                       Person p2(10);(调用有参构造)

                       Person p3(p2);(调用拷贝构造)

    ②显示法 :Person p1;

                       Person p2=Person(10);

                       Person p3=Person(p2);

    ③隐式转换法:Person p2=10; //相当于Person p2=Person(10);

                             Person p3=p2;

调用规则

①默认情况下,编译器至少给一个类添加三个函数:默认构造函数、析构函数、拷贝构造函数

②默认→有参(不提供)→拷贝 (从低级到高级) 

如果写了高级的构造函数,编译器不再提供低级的。

1.3.4 深浅拷贝

浅拷贝:编译器自带的拷贝构造函数,简单的赋值拷贝

深拷贝:在堆区申请空间

           在下面的例子中,编译器自带的拷贝构造实现的功能:m_age=age; m_high=high;

浅拷贝带来的重复释放问题用深拷贝解决:如果属性有在堆区开辟的,一定要自己提供一个拷贝构造函数。

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

class Person
{
public:
	Person()
	{
		cout << "默认构造" << endl;
	}
	Person(int age,int high )
	{
		m_age = age;
		m_high = new int(high);
		cout << "有参构造" << endl;
	}
	Person(const Person&p)
	{
		m_age = p.m_age;
		m_high = new int(*p.m_high); //深拷贝关键
		cout << "深拷贝" << endl;
	}
	~Person()//析构代码:将堆区开辟的数据释放
	{
		if (m_high != NULL)
		{
			delete m_high;
			m_high = NULL;
		}
		cout << "析构" << endl;
	}
	int m_age;  //年龄
	int* m_high;//身高(堆区)
};
void test(void)
{
	Person p1(18, 160);
	cout << "p1的年龄:" << p1.m_age << "身高:" << *p1.m_high << endl;
	Person p2(p1);
	cout << "p2的年龄:" << p2.m_age << "身高:" << *p2.m_high << endl;
}

int main()
{
	test();
	system("pause");
	return 0;
}

1.4 初始化列表

传统方式赋初值

	Person(int a,int b,int c)
	{
		m_a = a;
		m_b = b;
		m_c = c;
	}

初始化列表赋初值

         Person(int a, int b, int c) :m_a(a), m_b(b), m_c(c)   {}

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

class Person
{
public:
	Person(int a, int b, int c) :m_a(a), m_b(b), m_c(c) 
	{

	}
	
	int m_a;
	int m_b;
	int m_c;
};
int main()
{
	Person p1(1,2,3);
	cout << p1.m_a << " " << p1.m_b << " " << p1.m_c << endl;
	system("pause");
	return 0;
}

1.5 类对象作为类成员

类比结构体嵌套:

比如B中有A的对象,先有A,后有B

构造函数和析构函数的执行顺序:A构造→B构造→B析构→A析构

静态成员

所有对象共享一份数据

2.1 静态成员变量

特点: ①编译阶段分配内存

            ②类内声明,类外初始化

            ③静态成员也是有访问权限的,私有成员,类外访问不到  

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

class Person
{
public:
	int m_c;
	static int m_a;  //类内声明
	static void func()
	{
		m_a = 0;//静态成员函数可以访问静态成员变量
	/*	m_c = 0;*/   //报错 
		cout << "调用静态函数" << endl;
	}
private:
	static int m_b;
};

int Person::m_a = 100; //类外初始化
int Person::m_b = 200; 


int main()
{
	Person p1;
	cout << p1.m_a << endl;
	p1.func();
	cout << p1.m_a << endl;
	//cout << p1.m_b << endl;//私有属性,类外访问不到
	system("pause");
	return 0;
}

2.2 静态成员函数

          静态成员函数只能访问静态成员变量

2.3 访问

①通过对象访问

	Person p1;
	p1.m_a;
	p1.func();

②通过类名访问:不创建对象也可以直接访问

Person::m_a;
Person::func();

2.4 存储

*空的类占用一个字节

*只有非静态成员变量属于类本身

可以用sizeof验证:(只有m_a 占用类的空间)

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

class Person
{
	int m_a;
    static int m_b;
	void func(void)
	{
		cout << " " << endl;
	}
	static void func2(void)
	{
		cout << "111" << endl;
	}
};
int main()
{
	Person p1;
	cout << sizeof(p1);

	system("pause");
	return 0;
}

this指针

3.1 定义

本质:指针常量(指向不可变)

特点:不用定义,直接使用(隐含在每一个非静态成员函数中);谁调用指向谁

用途

解决名称冲突:当函数形参和成员变量同名时,用来区分

class Person
{
public:
	void func(int age)
	{
		age = this->age;
	}
	int age;
};

返回对象本身用*this

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

class Person
{
public:
	Person& addAge(Person& p)
	{
		this->age += p.age;
		return *this;
	}
	int age;
};

int main()
{
	Person p1;
	p1.age = 10;
	Person p2(p1);
	
	p2.addAge(p1).addAge(p1).addAge(p1);
	cout << p2.age << endl;
	cout << p1.age << endl;

	system("pause");
	return 0;
}

3.2 空指针访问成员函数

解决方法

		if (this == NULL)
		{
			return;
		}

整段代码

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

class Person
{
public:
	void func1()
	{
		cout << "111" << endl;
	}
	void func2()  
	{       
		if (this == NULL)
		{
			return;
		}
		cout << "age=" << m_age <<endl;
	}
	int m_age;
};

int main()
{
	Person* p = NULL;
	p->func1();
	//p->func2();

	system("pause");
	return 0;
}

const修饰成员函数

常函数:①成员函数加const修饰后,成为常函数

              ②常函数内部不可以修改成员属性

              ③成员属性声明时加关键字mutable后,在常函数中依然可以修改

在成员函数后面加const,修饰的是this指针,相当于使指针的值也不可以修改

class Person
{
public:
	void func1()
	{
		m_a = 100;         //this->m_a=100,指向调用它的对象
		/*this = NULL;*/   //this指针指向不能修改
	}
	void func2()const  //常函数
	{       
		/*m_a = 200;*/  //不可修改成员属性
		m_b = 100;
	}
	int m_a;
	mutable int m_b;
};

常对象:①声明对象前加const,成该对象为常对象

               ②常对象只能调用常函数

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

class Person
{
public:
	void func1() const
	{
	}
	void func2() 
	{
		m_a = 10;
	}
	int m_a;
};

int main()
{
    const Person p1;  //常对象
	//p1.m_a = 100;   //常对象不能修改属性
	/*p1.func1();*/   //常对象不能调用普通成员函数,因为普通成员函数可以修改属性
	system("pause");
	return 0;
}

友元

友元的目的就是让一个函数/类访问另一个类中的私有成员

4.1 全局函数作友元

friend +函数声明

注意书写顺序:类→函数→所有类外初始化

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

class A
{
	friend void func(A* aa);
public:
	A()
	{
		a1 = 1;
		a2 = 2;
	}
public:
	int a1;
private:
	int a2;
};

void func(A*aa)
{
	cout << "友元访问A的公有成员" << aa->a1 << endl;
	cout << "友元访问A的私有成员" << aa->a2 << endl;
}

int main()
{
	A aa;
	func(&aa);

	system("pause");
	return 0;
}

4.2 友元类

(类作友元)注意书写顺序:类→函数→所有类外初始化

friend+类声明

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

class A
{
	friend class B;
public:
	A();
public:
	int a1;
private:
	int a2;
};
A::A()
{
	a1 = 1;
	a2 = 2;
}

class B
{
public:
	B();
	void visit();
	A* aa;
};
B::B()
{
	aa = new A;
}
void B::visit()
{
	cout << "友元类正在访问A的共有成员" << aa->a1 << endl;
	cout << "友元类正在访问A的私有成员" << aa->a2<< endl;
}


int main()
{
	B bb;
	bb.visit();

	system("pause");
	return 0;
}

4.3 成员函数作友元

friend +作用域+函数声明

书写顺序:声明A→类B→类A→所有类外初始化

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

class A;

class B
{
public:
	B();
	void visit1();
	void visit2();
	A* aa;
};
class A
{
	friend void B::visit1();
public:
	A();
public:
	int a1;
private:
	int a2;
};



A::A()
{
	a1 = 1;
	a2 = 2;
}

B::B()
{
	aa = new A;
}

void B::visit1()
{
	cout << "友(成员函数)正在访问A的公有成员" << aa->a1 << endl;
	cout << "友(成员函数)正在访问A的私有成员" << aa->a2 << endl;
}
void B::visit2()
{
	cout << "普通成员函数正在访问A的公有成员" << aa->a1 << endl;
}


int main()
{
	B bb;
	bb.visit1();
	bb.visit2();
	system("pause");
	return 0;
}

运算符重载

实现自定义数据类型的运算

5.1 加号运算符重载

实现两个自定义数据类型相加

全局函数

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

class Person
{
public:
	Person();
	int m_a;
	int m_b;
};
Person::Person()
{
	m_a = 1;
	m_b = 2;
}

Person operator+(Person &p1,Person p2)
{
	Person temp;
	temp.m_a = p1.m_a + p2.m_a;
	temp.m_b = p1.m_b + p2.m_b;
	return temp;
}

int main()
{
	Person p1;
	Person p2;
	Person p3 = p1 + p2;
	cout << p3.m_a << endl;
	cout << p3.m_b << endl;
	system("pause");
	return 0;
}

局部函数(成员函数): 

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

class Person
{
public:
	Person();
	Person operator+(Person p)
	{
		Person temp;
		temp.m_a = p.m_a + this->m_a;
		temp.m_b = p.m_b + this->m_b;
		return temp;
	}
	int m_a;
	int m_b;
};
Person::Person()
{
	m_a = 1;
	m_b = 2;
}



int main()
{
	Person p1;
	Person p2;
	Person p3 = p1 + p2;
	cout << p3.m_a << endl;
	cout << p3.m_b << endl;
	
	system("pause");
	return 0;
}

5.2 左移运算符重载

只能用全局函数

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

class Person
{
public:
	Person();
	int m_a;
	int m_b;
};
Person::Person()
{
	m_a = 1;
	m_b = 2;
}

ostream& operator<<(ostream&cout,Person p)
{
	cout << p.m_a << " " << p.m_b << " ";
	return cout;
}


int main()
{
	Person p1;
	Person p2;
	p2.m_a = 5;
	p2.m_b = 4;
	cout << p1<<p2;
	
	system("pause");
	return 0;
}

5.3 递增运算符重载

前置和后置用int区分

前置可以实现连续运算:因此需要返回对象本身,要用引用的方式 ++(++p)

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

class Person
{
public:
	Person();
	Person operator++(int);  //后置递增 a++
	Person& operator++(); //前置递增 ++a
	int m_a;

};
Person::Person()
{
	m_a = 1;
}
Person Person::operator++(int)
{
	Person temp = *this;
	this->m_a++;
	return temp;
}
Person& Person::operator++()
{
	m_a++;
	return *this;
}
ostream& operator<<(ostream& cout, Person p)
{
	cout << p.m_a;
	return cout;
}


int main()
{
	Person p1;
	cout << p1 << endl;
	cout << p1++<< endl;
	cout << p1 << endl;

	cout << "当前p为" << p1 << endl;
	cout << ++p1 << endl;
	cout << ++(++p1) << endl;
	system("pause");
	return 0;
}

5.4 赋值运算符重载

c++编译器会提供“=”,对属性进行值拷贝;但是当对队堆区的数据进行值拷贝时,会出现“浅拷贝问题”

之前是用自己重写拷贝构造函数解决的,也可以使用赋值运算符重载解决

	Person(const Person&p)
	{
		m_age = p.m_age;
		m_high = new int(*p.m_high);
	}

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

class Person
{
public:
	Person(int high);
	Person& operator=(Person &p);
	~Person();
	int* m_high;

};
Person::Person(int high)
{
	m_high = new int(high);
}
Person& Person::operator=(Person &p)
{
	if (m_high != NULL)
	{
		delete m_high;
		m_high = NULL;
	}
	m_high = new int(*p.m_high);
	return *this;
}

Person::~Person()
{
	if (m_high != NULL)
	{
		delete m_high;
		m_high = NULL;
	}
}

void test()
{
	Person p1(165);

	Person p2(0);
	Person p3(0);

	p2 = p3 = p1;
	cout << *p2.m_high << endl;
	cout << *p3.m_high << endl;
}
int main()
{
	
	test();
	system("pause");
	return 0;
}

5.5 关系运算符重载

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

class Person
{
public:
	bool operator>=(Person p);
	int m_age;

};

bool Person::operator>=(Person p)
{
	if (m_age >= p.m_age)
	{
		return true;
	}
	else
	{
		return false;
	}
}


int main()
{
	Person p1;
	Person p2;
	p1.m_age=10;
	p2.m_age=20;

	cout << (p1 >= p2) <<endl;

	system("pause");
	return 0;
}

5.6 函数调用运算符重载

称为仿函数,没有固定写法,很灵活

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

class xxx
{
public:
	void operator()(string a)
	{
		cout << a << endl; //实现功能:把传进来的字符串打印出来
	}
};

int main()
{
	xxx myprint;//创建对象print
	myprint("hello");

	system("pause");
	return 0;
}

继承

 子类除了继承了父类的特征(共性),还有自己的特性。

意义:减少重复代码

6.1 基本语法

语法: class Son:public father  {};

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

class father
{
public:
	void Ffunc()
	{
		cout << "***" << endl;
	}
};
class SonA:public father
{
public:
	void sfunc()
	{
		cout << "AAA" << endl;
	}
};
class SonB :public father
{
public:
	void sfunc()
	{
		cout << "BBB" << endl;
	}
};
class SonC :public father
{
public:
	void sfunc()
	{
		cout << "CCC" << endl;
	}
};
int main()
{
	SonA son1;
	SonB son2;
	SonC son3;
	son1.Ffunc();
	son1.sfunc();
	cout << endl;
	son2.Ffunc();
	son2.sfunc();
	cout << endl;
	son3.Ffunc();
	son3.sfunc();
	cout << endl;
	system("pause");
	return 0;
}

6.2 继承方式

子类访问不到父类的私有成员

class Son:public father {};

公有方式:继承到的父类中各个成员的访问权限不变

class Son:public father {};

保护方式:继承到的父类中各个成员的访问权限都变成保护权限

class Son:public father {};

私有方式:继承到的父类中各个成员的访问权限都变成了私有权限

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

class father
{
public:
	int a=1;
protected:
	int b=2;
private:
	int c=3;
};

class SonA:public father 
{
public:
	void func()
	{
		cout << a << endl;
		cout << b << endl;
	}
};
class SonB :protected father 
{
	void func()
	{
		cout << a << endl;
		cout << b << endl;
	}
};
class SonC :private father {};
//自己内部也可以访问到父类的a和b两个成员,但是自己的子类继承自己后访问不到

int main()
{
	
	SonA son;
	son.func();
	son.a;//以公有方式继承父类的成员,在类外可以访问到父类中的公有成员
	SonB son2;
	//son2.a;  以保护方式继承父类的成员,在类外访问不到
	system("pause");
	return 0;
}

6.3 对象模型

父类中所有非静态成员属性都会被子类继承,只不过父类中的私有成员会被编译器隐藏,子类访问不到

6.4 构造和析构顺序

父类构造→子类构造

子类析构→父类析构

6.5 同名成员处理

当子类和父类的成员同名时:

访问子类:直接访问             

访问父类:加(父类)作用域再访问

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

class father
{
public:
	int a=1;
};

class Son:public father 
{
public:
	int a = 2;
};


int main()
{
	Son son;
	cout << son.a << endl;//访问子类的同名成员
	cout << son.father::a << endl;  //访问父类的同名成员
	system("pause");
	return 0;
}

6.6 同名静态成员处理

同名静态成员和同名非静态成员的处理方式相同

静态成员的访问方式有两种:通过类名访问、通过对象访问

静态成员:一定要类内声明,类外初始化

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

class father
{
public:
	 static int a;
};
int father::a = 1;

class Son:public father 
{
public:
	static int a;
};
int Son::a = 2;

int main()
{
	//1.通过类名访问
	cout << Son::a << endl;//访问子类的静态同名成员
	cout << Son::father::a << endl;  //访问父类的静态同名成员
	//2.通过对象访问
	Son son;
	cout << son.a << endl;//访问子类的静态同名成员
	cout << son.father::a << endl;  //访问父类的静态同名成员

	system("pause");
	return 0;
}

6.7 多继承语法

c++允许一个类继承多个类

语法:class Son:public father1,public father2,protected father3  {};

6.8 菱形继承

两个派生类继承了同一个基类,又有某个类同时继承了两个派生类

产生问题:“某类”继承从父类中继承了两份数据,造成资源浪费和二义性,利用虚继承解决duo

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

class father
{
public:
	int m_high=180;
};

class Son1 :virtual public father 
{
public:
	Son1()
	{
		m_high = 160;
	}
};
class Son2 :virtual public father
{
public:
	Son2()
	{
		m_high = 150;
	}
};
class Grandson : public Son2 ,public Son1{};
//后继承的Son1中的m_high覆盖Son2,菱形继承后输出的是Son1
int main()
{
	Grandson gson;
	cout << gson.m_high << endl;

	system("pause");
	return 0;
}

多态

多种形态:“去完成某个任务,不同的人做出来不同的效果”

7.1 分类

静态多态:函数地址早绑定 (函数重载、运算符重载、复用函数名)

动态多态函数地址晚绑定(多态)

7.2 基本语法

动态多态满足条件:

①有继承关系

②子类重写父类中虚函数

重写≠重载,对于重写,函数名返回值类型数量等完全相同

多态使用:

父类的指针或引用指向子类对象

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

class Animal
{
public:
	//加了virtual:地址晚绑定
	virtual void speak()
	{
		cout << "动物在说话" << endl;
	}
};

class Cat:public Animal
{
public:
	void speak()
	{
		cout << "小猫在说话" << endl;
	}
};

class Dog:public Animal
{
public:
	void speak()
	{
		cout << "狗狗在说话" << endl;
	}
};

void doSpeak(Animal &animal)
{
	animal.speak();
}

int main()
{
	Cat cat;
	doSpeak(cat);
	Dog dog;
	doSpeak(dog);
	system("pause");
	return 0;
}

7.3 原理

父类的虚函数带来一个指针,指向函数的入口地址,指向谁就调用谁的(同名)函数

7.4 案例一:计算器

使用引用AddCalculator addc;     AbstractCalculator &c=addc;

使用指针AbstractCalculator*c=new Addc; //记得释放堆区数据

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

class Calculator
{
public:
	int getResult(string oper)
	{
		if (oper == "+")
		{
			return m_Num1 + m_Num2;
		}
		if (oper == "-")
		{
			return m_Num1 - m_Num2;
		}
		if (oper == "*")
		{
			return m_Num1 * m_Num2;
		}
	}
	int m_Num1;
	int m_Num2;
};//如果想扩展新的功能,需要修改源码


//利用多态实现计算器的抽象类(基类)
class AbstractCalculator
{
public:
	virtual int getResult()
	{
		return 0;
	}
	int m_Num1;
	int m_Num2;
};
//1.加法计算器继承抽象类
class AddCalculator :public AbstractCalculator
{
public://子类virtual可写可不写
	virtual int getResult()
	{
		return m_Num1 + m_Num2;
	}
};

//2.减法计算器继承抽象类
class SubCalculator :public AbstractCalculator
{
public://子类virtual可写可不写
	virtual int getResult()
	{
		return m_Num1 - m_Num2;
	}
};

void test01()
{
	Calculator c;
	c.m_Num1 = 5;
	c.m_Num2 = 1;
	int result = c.getResult("*");
	cout << result << endl;
}

void test02()
{
	AbstractCalculator* c = new AddCalculator;//父类指针指向子类对象
	c->m_Num1 = 1;
	c->m_Num2 = 2;
	cout << c->getResult()<<endl ;
	delete c;//堆区数据记得释放

	c = new SubCalculator;//父类指针指向子类对象
	c->m_Num1 = 1;
	c->m_Num2 = 2;
	cout << c->getResult() << endl;
	delete c;//堆区数据记得释放
}
int main()
{
	test02();
	system("pause");
	return 0;
}

7.5 优点

1.组织结构清晰

2.可读性强

3.利于前期和后期的扩展和维护

7.6 纯虚函数和抽象类

在多态中,父类中的虚函数通常是毫无意义的,主要调用子类重写的内容,因此可以将虚函数改为纯虚函数

语法:virtual void func()=0;

当类中有了纯虚函数,这个类也称为抽象类

抽象类特点

①无法实例化对象

②子类必须重写抽象类中的纯虚函数

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

class Base
{
public:
	//纯虚函数:这类类只要有一个纯虚函数,就属于抽象类
	virtual void func() = 0;
};

class Son :public Base//2.子类必须重写父类中的纯虚函数,否则也属于抽象类
{
	virtual void func() 
	{
		cout << "调用子类函数" << endl;
	}
};


int main()
{
	//Base b;         //1.栈和堆区都无法实例化对象
	//new Base;

	//Base* b = new Son;
	//b->func();

	Son s;
	Base &b= s;
	b.func();

	system("pause");
	return 0;
}

7.7 案例二:制作饮品

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

class AbstractDrinking
{
public:
	virtual void Boil() = 0;
	virtual void Brew() = 0;
	virtual void PutInCup() = 0;
	virtual void PutSomething() = 0;
	void makeDrink()
	{
		Boil();
		Brew();
		PutInCup();
		PutSomething();
	}
};

class Coffee:public AbstractDrinking
{
public:
	virtual void Boil()
	{
		cout << "煮农夫山泉" << endl;
	}
	virtual void Brew()
	{
		cout << "冲泡咖啡" << endl;
	}
	virtual void PutInCup()
	{
		cout << "倒入杯中" << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入糖和牛奶" << endl;
	}
};

class Tea :public AbstractDrinking
{
public:
	virtual void Boil()
	{
		cout << "煮农夫山泉" << endl;
	}
	virtual void Brew()
	{
		cout << "冲泡茶叶" << endl;
	}
	virtual void PutInCup()
	{
		cout << "倒入杯中" << endl;
	}
	virtual void PutSomething()
	{
		cout << "加入柠檬" << endl;
	}
};
void doWork(AbstractDrinking *abs)
{
	abs->makeDrink(); //调用接口
	delete abs;
}

void test()
{
	doWork(new Coffee);
}
int main()
{
	test();
	system("pause");
	return 0;
}

7.8 虚析构和纯虚析构

虚析构和纯虚析构的共性

①可以解决父类指针释放子类对象不干净的问题

②都要有具体的函数实现

区别

有纯虚析构属于抽象类,无法实例化对象

父类指针在析构的时候 不会调用子类中的析构函数,导致子类如果有堆区属性,出现内存泄漏

纯虚析构:类外写一下实现

virtual ~Animal() = 0;

Animal:: ~Animal()
{
}
#include <iostream>
#include <string>
using namespace std;

class Animal
{
public:
	Animal()
	{
		cout << "Animal构造函数" << endl;
	}
	virtual ~Animal()
	{
		cout << "Animal析构函数" << endl;
	}
	virtual void speak() = 0;
};

class Cat:public Animal
{
public:
	Cat(string name)
	{
		cout << "Cat构造" << endl;
		m_name = new string(name);
	}
	~Cat()
	{
		if (m_name != NULL)
		{
			cout << "Cat析构" << endl;
			delete m_name;
			m_name = NULL;
		}
	}
	virtual void speak()
	{
		cout << *m_name<<"小猫在说话" << endl;
	}
	string *m_name;
};

void test01()
{
	Animal* animal = new Cat("Tom");
	animal->speak();
	delete animal;
}

int main()
{
	test01();
	system("pause");
	return 0;
}

7.9 案例三:电脑组装

需求://案例描述
电脑组成部分:CPU、显卡、内存条
将每个零件封装成抽象基类,并且提供不同厂商生产不同的零件
创建电脑类提供让电脑工作的函数,并调用每个零件工作的接口
测试时组装三台不同的电脑进行工作

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

class CPU
{
public:
	virtual void calculate() = 0;
};
class VideoCard
{
public:
	virtual void display() = 0;
};
class Memory
{
public:
	virtual void storage() = 0;
};

class Computer
{
public:
	Computer(CPU* cpu, VideoCard* vcard, Memory* Mem)
	{
		m_cpu = cpu;
		m_vcard = vcard;
		m_Mem = Mem;
	}
	~Computer()
	{
		if (m_cpu != NULL)
		{
			delete m_cpu;
			m_cpu = NULL;
		}
		if (m_vcard != NULL)
		{
			delete m_vcard;
			m_vcard = NULL;
		}
		if (m_Mem != NULL)
		{
			delete m_Mem;
			m_Mem = NULL;
		}
	}
	void dowork()
	{
		m_cpu->calculate();
		m_vcard->display();
		m_Mem->storage();
	}
private:
	CPU* m_cpu;
	VideoCard* m_vcard;
	Memory* m_Mem;
};

class IntelCPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "Intel的CPU开始计算了" << endl;
	}
};
class IntelVideoCard :public VideoCard
{
public:
	virtual void display()
	{
		cout << "Intel的显卡开始显示了" << endl;
	}
};
class IntelMemory :public Memory
{
public:
	virtual void storage()
	{
		cout << "Intel的内存开始存储了" << endl;
	}
};

class LenovoCPU :public CPU
{
public:
	virtual void calculate()
	{
		cout << "联想的CPU开始计算了" << endl;
	}
};
class LenovoVideoCard :public VideoCard
{
public:
	virtual void display()
	{
		cout << "联想的显卡开始显示了" << endl;
	}
};
class LenovoMemory :public Memory
{
public:
	virtual void storage()
	{
		cout << "联想的内存开始存储了" << endl;
	}
};

void test()
{
	Computer c1(new IntelCPU, new IntelVideoCard, new IntelMemory);
	c1.dowork();
	cout << "*********************" << endl;
	Computer c2(new LenovoCPU, new LenovoVideoCard, new IntelMemory);
	c2.dowork();
}
int main()
{
	test();
	system("pause");
	return 0;
}

文件操作

8.1 写文本文件

void test01()
{
	ofstream ofs;
	ofs.open("test.txt",ios::out);
	ofs << "张三:男" << endl;
	ofs << "李四:男" << endl;
	ofs << "王五:女" << endl;
	ofs.close();
}

8.2 读文件

ifs.is_open()                     判断文件是否打开,如果打开成功,返回true

void test02()
{
	ifstream ifs;
	ifs.open("test.txt",ios::in);
	//判断是否打开成功
	if (!ifs.is_open())
	{
		cout << "文件打开失败" << endl;
		return;
	}
	//读文件操作
	char arr[1024] = { 0 };
	while (ifs >> arr)
	{
		cout << arr << endl;
	}
	ifs.close();
}
//读文件操作
string word;
while (ifs >> word)
{
	cout << word << endl;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值