目录
1.定义一个基类 Animal,其中有一个虚函数 perform(),用于在子类中实现不同的表演行为。
一、菱形继承
1.1 概念
1.2 格式
A --------公共基类
/ \
B C ------- 中间子类
\ /
D --------汇聚子类
解决:虚继承
#include <iostream>
using namespace std;
//封装公共基类 家具 类
class Jiaju
{
private:
string color;
public:
//无参构造
Jiaju() {cout << "家具的无参构造函数" << endl;}
//有参构造
Jiaju(string n):color(n)
{
cout << "家具的有参构造函数" << endl;
}
};
//中间子类
//封装 沙发的类
class Sofa:public Jiaju
{
private:
string sitting;
public:
//无参构造
Sofa() {cout << "沙发的无参构造" << endl;}
//有参构造函数
Sofa(string s,string c):Jiaju(c),sitting(s)
{
cout << "沙发的有参构造" << endl;
}
void display()
{
cout << sitting << endl;
}
};
//中间子类
//封装 床 类
class Bed:public Jiaju
{
private:
string sleep;
public:
//无参
Bed() {cout << "床的无参构造" << endl;}
//有参
Bed(string s,string c):Jiaju(c),sleep(s)
{
cout << "床的有参构造" << endl;
}
void display()
{
cout << sleep << endl;
}
};
//汇聚子类
//封装 沙发床类 继承于沙发 和 床
class Sofa_Bed:public Bed,public Sofa
{
private:
int w;
public:
//
Sofa_Bed(){cout << "沙发床的无参构造" << endl;}
//有参构造
Sofa_Bed(string sit, string s, int w,string c):Bed(s,c),Sofa(sit,c),w(w)
{
cout << "沙发床的有参构造" << endl;
}
};
int main()
{
// Sofa_Bed s;
Sofa_Bed s1("可坐","可躺",123,"pink");
return 0;
}
二、虚继承
2.1 作用
2.2 格式
在中间子类的继承方式前 加上 virtual
class 类名 : virtual 继承方式 类名 //中间子类
{
中间子类的拓展;
};
2.3注意
#include <iostream>
using namespace std;
//封装公共基类 家具 类
class Jiaju
{
private:
string color;
public:
//无参构造
Jiaju() {cout << "家具的无参构造函数" << endl;}
//有参构造
Jiaju(string n):color(n)
{
cout << "家具的有参构造函数" << endl;
}
};
//中间子类
//封装 沙发的类
class Sofa:virtual public Jiaju //中间子类虚继承公共基类
{
private:
string sitting;
public:
//无参构造
Sofa() {cout << "沙发的无参构造" << endl;}
//有参构造函数
Sofa(string s,string c):Jiaju(c),sitting(s)
{
cout << "沙发的有参构造" << endl;
}
void display()
{
cout << sitting << endl;
}
};
//中间子类
//封装 床 类
class Bed:virtual public Jiaju //中间子类虚继承公共基类
{
private:
string sleep;
public:
//无参
Bed() {cout << "床的无参构造" << endl;}
//有参
Bed(string s,string c):Jiaju(c),sleep(s)
{
cout << "床的有参构造" << endl;
}
void display()
{
cout << sleep << endl;
}
};
//汇聚子类
//封装 沙发床类 继承于沙发 和 床
class Sofa_Bed:public Bed,public Sofa
{
private:
int w;
public:
//
Sofa_Bed(){cout << "沙发床的无参构造" << endl;}
//有参构造
Sofa_Bed(string sit, string s, int w,string c):Jiaju(c),Bed(s,c),Sofa(sit,c),w(w) //需要在汇聚子类中显性调用公共基类的有参构造函数
{
cout << "沙发床的有参构造" << endl;
}
};
int main()
{
// Sofa_Bed s;
Sofa_Bed s1("可坐","可躺",123,"pink");
return 0;
}
三、多态
一种形式多种状态
多态就像一个人,可以有很多角色或者行为,取决于不同情境
父类的指针或者引用,指向或初始化子类的对象,调用子类对父类重写的函数,进而展开子类的功能。
3.1函数重写
3.2 虚函数
#include <iostream>
using namespace std;
// 封装 周 这个类
class Zhou
{
private:
string name;
int age;
public:
//无参构造
Zhou() {}
//有参构造函数
Zhou(string n, int a):name(n),age(a)
{}
//
virtual void speek() //表示该函数是虚函数
{
cout << "阿巴阿巴。。" << endl;
}
};
//封装 周老师 类,继承于周类
class Teacher:public Zhou
{
private:
int id;
public:
//无参构造
Teacher() {}
//有参构造
Teacher(string n, int a, int d):Zhou(n,a),id(d)
{}
//
void speek()
{
cout << "看我,上多态,认真听讲" << endl;
}
};
//封装 游戏玩家 类 继承于Zhou类
class Player:public Zhou
{
private:
string game;
public:
//。。
Player() {}
//有参构造
Player(string name, int age, string g):Zhou(name,age),game(g)
{}
//
void speek()
{
cout << "稳住,我们能赢" << endl;
}
};
int main()
{
Teacher t("zhangsan",34,1001);
Zhou *p; //父类的指针
p = &t; //父类的指针,指向子类对象 相当于承当老师这个角色
p->speek(); // 上课
Player g("lisi",45,"王者");
p = &g; //此时是游戏玩家这个角色
p->speek();
return 0;
}
3.3 赋值兼容规则
父类的指针或者引用,指向或初始化子类的对象
3.4 多态中,函数重写的原理
3.5 虚析构函数
虚析构函数用来解决 父类指针指向子类时,父类指针释放,导致子类自拓展的空间没有得到释放
3.5.1 格式
virtual 析构函数
{}
#include <iostream>
using namespace std;
//封装 人 类
class Person
{
private:
string name;
public:
//
Person() {}
//有参构造函数
Person(string n):name(n)
{
}
virtual ~Person() //虚析构函数 满足继承
{
cout << "Person::析构函数" << endl;
}
};
//封装 学生 继承于人
class Stu:public Person
{
private:
int id;
public:
//
Stu(){}
//有参构造
Stu(string n , int i):Person(n),id(i)
{}
~Stu()
{
cout << "Stu::析构函数" << endl;
}
};
int main()
{
Person *p = new Stu("张三",1001);
delete p; //如果没有虚析构函数,进行释放p是,子类自己拓展的空间就没有释放--内存泄漏
return 0;
}
3.6 纯虚函数
当父类中虚函数被子类用来重写,且没有定义的意义,这个时候,一般把父类中的虚函数设置成纯虚函数。
3.6.1格式
virtual 函数返回值类型 函数名(形参列表) = 0; //纯虚函数
四、抽象类
#include <iostream>
using namespace std;
//..
class A //抽象类
{
private:
int a;
public:
A() {}
virtual void show() = 0; //纯虚函数
};
class B:public A
{
public:
B() {}
void show() //如果子类没有对父类的纯虚函数重写,那么子类也是抽象类,不能实例化一个对象
{}
};
int main()
{
B b;
return 0;
}
五、模板
5.1模板的特点
5.2 函数模板
5.2.1作用
建立一个通用的函数,其返回值类型或者形参类型 不具体制定,用一个虚拟的类型来代替。
5.2.2 格式
template <typename T>
函数的声明或定义
解释:
template ----->表示开始创建模板
typename -->表明后面的符号是数据类型,typename 也可以用class代替
T ----->表示数据类型,可以其他符号代替
#include <iostream>
using namespace std;
//创建函数模板
template <typename T>
void fun(T &a, T &b)
{
T temp;
temp = a;
a = b;
b = temp;
}
//void fun(int &a, int &b)
//{
// int temp;
// temp = a;
// a = b;
// b = temp;
//}
//void fun(double &a, double &b)
//{
// double temp;
// temp = a;
// a = b;
// b = temp;
//}
//void fun(char &a, char &b)
//{
// char temp;
// temp = a;
// a = b;
// b = temp;
//}
int main()
{
int a = 10, b = 20;
fun(a,b);
cout << a << " " << b << endl;
double c = 1.3, d = 1.4;
fun(c, d);
cout << c << " " << d << endl;
return 0;
}
六、练习
1.定义一个基类 Animal,其中有一个虚函数 perform(),用于在子类中实现不同的表演行为。
#include <iostream>
using namespace std;
class Animal{
protected:
string species;
public:
Animal(){}
Animal(string sp): species(sp)
{}
virtual void perform(){}
};
class lion:public Animal{
public:
lion(){}
lion(string species):Animal(species)
{
}
void perform(){
cout << Animal::species << "跳火圈" << endl;
}
};
class elephant:public Animal{
public:
elephant(){}
elephant(string sp):Animal(sp)
{
}
void perform(){
cout << Animal::species << "踩背" << endl;
}
};
class monkey:public Animal{
public:
monkey(){}
monkey(string sp):Animal(sp)
{
}
void perform(){
cout << Animal::species << "偷桃" << endl;
}
};
int main()
{
lion it1("辛巴");
Animal *p;
p = &it1;
p->perform();
elephant it2("非洲象");
p = &it2;
p->perform();
monkey it3("峨眉山猴子");
p = &it3;
p->perform();
return 0;
}
结果为:
2.用函数模板实现不同数据类型的交换功能。
#include <iostream>
using namespace std;
template <typename T>
void fun(T *a, T *b)
{
T temp;
temp = *a;
*a = *b;
*b = temp;
}
int main()
{
int a = 10;
int b = 50;
char c = 'C';
char d = 'D';
fun(&a,&b);
fun(&c,&d);
cout << "a = " << a << " b = " << b << endl;
cout << "c = " << c << " d = " << d << endl;
return 0;
}