一、继承
在基类基础上创立一个新的类,新类中继承了基类了内容,同时可以添加自己独有的内容,简化了程序
已经存在的类成为基类或父类;
从父类或基类基础上新建的类成为派生类或子类
#include <iostream>
using namespace std;
class Father{
public://公共部分
string first_name="王";
void work(){
cout<<"厨师"<<endl;
}
};
//说明Son类是Father类的派生类,继承了Father的内容
class Son:public Father{
public:
void work(){//对基类内容修改
cout<<"程序员"<<endl;
}
void play(){//创建属于自己的内容
cout<<"游戏"<<endl;
}
};
int main(){
Son s;
cout<<s.first_name<<endl;//王
s.work();//程序员
s.play();//游戏
}
需要调用基类的代码来完成派生类中基类代码内存的开辟。 派生类的任意一个构造函数,都必须直接或者间接调用基类的任意一个构造函数
1、1 透传构造
派生类中的构造函数调用基类的构造函数
#include <iostream>
using namespace std;
class Father{//基类
private://私有
string first_name;
int age;
public:
Father(string name){//一个参数的基类函数
this->first_name=name;
}
Father(string name,int age){//两个参数的基类函数
this->first_name=name;
this->age=age;
}
void show(){
cout<<first_name<<" "<<age<<endl;
}
};
class Son:public Father{
public:
Son(string name):Father(name){}//对应一个参数的基类函数
Son(string name,int age):Father(name,age){}//对应两个参数的基类函数
};
int main(){
Son s("张",45);
s.show();//张 45
Son s1("王");
s1.show();//王
}
1、2委托构造
某个类中的构造函数调用这个类中的重载的构造函数
#include <iostream>
using namespace std;
class Father{
private:
string first_name;
int age;
public:
Father(string name){
cout<<"Father 一个参数构造函数"<<endl;
this->first_name=name;
}
Father(string name,int age){
cout<<"Father 两个参数构造函数"<<endl;
this->first_name=name;
this->age=age;
}
void show(){
cout<<first_name<<" "<<age<<endl;
}
};
class Son:public Father{
public:
Son(string name):Son(name,18){cout<<"子类一个参数"<<endl;}
Son(string name,int age):Father(name,age){cout<<"子类两个参数"<<endl;}
};
int main(){
Son s("张",23);
s.show();//张 23
cout<<endl;
Son s1("王");
s1.show();//王
}
运行结果:
Father 两个参数构造函数
子类两个参数
张 23
Father 两个参数构造函数 (首先创建father类的构造函数)
子类两个参数 (然后创建两个参数的子类构造函数)
子类一个参数 (创建一个参数的子类构造函数)
王 18 (显示show)
对象的创建和销毁
#include <iostream>
using namespace std;
class Value{
private:
string name;
public:
Value(string name):name(name){
cout<<name<<"创建了"<<endl;
}
~Value(){
cout<<name<<"销毁了"<<endl;
}
};
class Father{
public:
static Value s_value; //s_value的类内声明
Value value=Value("Father类的成员变量");
Father(){//构造函数
cout<<"Father的构造函数"<<endl;
}
~Father(){//析构函数
cout<<"Father的析构函数"<<endl;
}
};
Value Father::s_value=Value("父类的静态Value"); //s_value的类外定义
class Son:public Father{
public:
static Value s_value; //s_value的类内声明
Value value=Value("Son类的成员变量");
Son(){
cout<<"Son的构造函数"<<endl;
}
~Son(){
cout<<"Son的析构函数"<<endl;
}
};
Value Son::s_value=Value("子类的静态Value"); //s_value的类外定义
int main()
{
cout<<"main方法开始"<<endl;
{
Son s;
cout<<"Son类对象使用中。。。"<<endl;
}
cout<<"main方法结束"<<endl;
}
运行结果:
父类的静态Value创建了
子类的静态Value创建了
main方法开始 //进入主函数
Father类的成员变量创建了
Father的构造函数
Son类的成员变量创建了
Son的构造函数
Son类对象使用中。。。 //son类对象使用中
Son的析构函数
Son类的成员变量销毁了
Father的析构函数
Father类的成员变量销毁了
main方法结束 //退出主函数
子类的静态Value销毁了
父类的静态Value销毁了
特点:
创建过程和销毁过程是对称的
同样的内容,父类先创建,然后派生类。销毁的时候先派生类 后父类
静态成员最先创建,最后销毁
继承 提高开发效率 但是会稍微降低运行效率
1、3 多重继承
一个派生类它有多个基类,会从多个基类中继承方法
#include <iostream>
using namespace std;
class Car{//车
public:
void driver(){
cout<<"可以驾驶"<<endl;
}
};
class House{//房子
public:
void sleep(){
cout<<"可以睡觉"<<endl;
}
};
class Carhouse:public Car,public House{
};
int main()
{
Carhouse s;//房车
s.driver();
s.sleep();
}
多重继承的二义性问题
当多个基类中有同名的成员。此时就会产生二义性
可以通过类名::方法来区分
#include <iostream>
using namespace std;
class Sofa{
public:
void sit(){
cout<<"可以坐着"<<endl;
}
void position(){
cout<<"放在客厅";
}
};
class Bed{
public:
void lay(){
cout<<"可以躺着"<<endl;
}
void position(){
cout<<"放在卧室";
}
};
class SofaBed:public Sofa,public Bed{
};
int main()
{
SofaBed s; //具有多种功能,放在不同的位置,使用::来区分
s.sit();
s.lay();
s.Sofa::position();
s.Bed::position();
}
2、权限
private (私有)本类中可以访问,在子类中不可以访问,在全局中不可以访问
protected (保护)本类中可以访问,在子类中可以访问,在全局中不可以访问
public (公共)本类中可以访问,在子类中可以访问,在全局中也可以访问
不管哪种继承方式,基类中私有的成员属性。都是不能直接访问
2、1 public继承
public继承之后 原来基类是什么权限,在派生类中还是什么权限
#include <iostream>
using namespace std;
class Father{
public:
string str1="public";
protected:
string str2="protected";
private:
string str3="private";
};
class Son:public Father{
public:
void show(){
cout<<str1<<endl;//public 可以访问
cout<<str2<<endl;//protected 可以访问
//cout<<str3<<endl;//父类私有不能访问
}
};
int main()
{
Son s;
s.show();
}
2、2 protected继承:
protected继承之后。所有继承过来的属性都会变成protected
#include <iostream>
using namespace std;
class Father{
public:
string str1="public";
protected:
string str2="protected";
private:
string str3="private";
};
class Son:protected Father{//子类
public:
void show(){
cout<<str1<<endl;//protected 可以访问
cout<<str2<<endl;//protected 可以访问
//cout<<str3<<endl;父类私有不能访问
}
};
class GrandSon:public Son{//孙子类
public:
void show(){
cout<<str1<<endl;
cout<<str2<<endl;
//cout<<str3<<endl;父类私有不能访问
}
};
int main()
{
Father f;
cout<<f.str1<<endl;
Son s;
cout<<s.str1<<endl; //在子类中变成了protected类型,在全局中不能访问
}
2、3 private继承
派生类私有继承之后 属性在派生中都变成私有.也就是下方的Son类中的属性都变成私有
#include <iostream>
using namespace std;
class Father{
public:
string str1="public";
protected:
string str2="protected";
private:
string str3="private";
};
class Son:private Father{
public:
void show(){
cout<<str1<<endl;
cout<<str2<<endl;
//cout<<str3<<endl;父类私有不能访问
}
};
class GrandSon:public Son{
public:
void show(){
// cout<<str1<<endl; //因为子类中变成私有 孙子类全访问不到
// cout<<str2<<endl;
}
};
int main()
{
Son s;
s.show();
GrandSon gs;
gs.show();
}
3、 多态
多态就是多种状态,可以一个接口实现多种状态。根据传入对象的不同,虽然调用同样接口,但选择不同的代码实现。
多态需要三种条件:
1. pubic继承
2. 派生类覆盖基类中的虚函数
3. 接口参数为基类对象的指针或者基类引,指向派生对象
虚函数:
virtual关键字修饰的函数就是虚函数
1. 当函数覆盖成功后,虚函数具有传递性。默认的函数都有virtual关键字
2. 成员函数和析构函数可以定义为虚函数。静态函数和构造函数不可以
3. 如果声明和定义分离时,virtual关键字只需要加在声明处。
没有使用多态的情况
这时指针是哪个对象定义的, 就调用哪个对象类型中的方法。
如下方Animal * ,就会执行Aniaml类中的方法
#include <iostream>
using namespace std;
class Animal{
public:
void eat(){
cout<<"吃东西"<<endl;
}
};
class Dog:public Animal{
public:
void eat(){
cout<<"吃狗粮"<<endl;
}
};
class House:public Animal{
public:
void eat(){
cout<<"吃草"<<endl;
}
};
int main()
{
Dog d;
d.eat();//吃狗粮
Animal *a=&d;
a->eat();//吃东西
}
3、1多态的实现
基类中函数用virtual修饰 派生类中 覆盖的函数后面加override 关键字。如果没有发生重写就会报错
#include <iostream>
using namespace std;
class Animal{
public:
virtual void eat(){
cout<<"吃东西"<<endl;
}
};
class Dog:public Animal{
public:
void eat()override{
cout<<"吃狗粮"<<endl;
}
};
class Cat:public Animal{
public:
void eat()override{
cout<<"吃鱼"<<endl;
}
};
int main()
{
Dog d;
d.eat(); //吃狗粮
Animal * a=&d;
a->eat(); //吃狗粮
Cat c;
Animal * b=&c;
b->eat(); //吃鱼
}
3、2 多态应用
接口使用多态
#include <iostream>
using namespace std;
class Animal{
public:
virtual void eat(){
cout<<"吃东西"<<endl;
}
};
class Dog:public Animal{
public:
void eat(){
cout<<"吃狗粮"<<endl;
}
};
class Cat:public Animal{
public:
void eat(){
cout<<"吃鱼"<<endl;
}
};
void test(Animal * a){//指针
a->eat();
}
void test2( Animal &b){//引用
b.eat();
}
int main()
{
//接口调用
Cat c2;
test2(c2);
test1(&c2);
}
基类指针或者基类引用(隐含继承)调用虚函数的时候,就是多态。触发查虚函数表
3.3多态可能出现的问题:
#include <iostream>
using namespace std;
class Animal{
public:
virtual void eat(){
cout<<"吃东西"<<endl;
}
~Animal(){
cout<<"Animal的析构函数"<<endl;
}
};
class Dog:public Animal{
public:
void eat(){
cout<<"吃狗粮"<<endl;
}
~Dog(){
cout<<"Dog类的析构函数"<<endl;
}
};
int main()
{
Animal * a=new Dog;
delete a; //只会调用Animal的析构函数
}
错误原因:
析构函数没有进行覆盖。实际析构函数也没法覆盖。但是可以把析构函数定义为虚函数
如果一个类可以能成为基类
4.抽象类(掌握)
抽象的概念。只有一些说明,没有具体实现,相当于一个框架的作用。抽象类中不具体的创建对象,不能作为参数类和和返回值类型
一个类中有纯虚函数,这个类就是抽象类;
如果一个类是抽象类,那么一定会有纯虚函数
如果继承了抽象类,需要实现全部实现,才能创建对象。否则它也会成为抽象类
#include <iostream>
using namespace std;
class Animal{
public:
virtual void eat(){
cout<<"吃东西"<<endl;
}
virtual ~Animal(){
cout<<"Animal的析构函数"<<endl;
}
};
class Dog:public Animal{
public:
void eat(){
cout<<"吃狗粮"<<endl;
}
~Dog(){
cout<<"Dog类的析构函数"<<endl;
}
};
int main()
{
// Dog * d=new Dog;
// delete d;
Animal * a=new Dog;
delete a;
}
#include <iostream>
using namespace std;
class Shape{
public:
virtual void area()=0;
virtual void perimeter()=0; //面积
};
class Rectangle:public Shape{
public:
void area(){
cout<<"长方形面积"<<endl;
}
void perimeter(){
cout<<"长方形的周长"<<endl;
}
};
int main()
{
Rectangle r;
r.area();
r.perimeter();
}
#include <iostream>
using namespace std;
class Shape{
public:
int a=10;
int b=5;
virtual void area()=0;
virtual void perimeter()=0;
};
class Rectangle:public Shape{
public:
void area(){
cout<<"长方形面积: "<<a*b<<endl;
}
void perimeter(){
cout<<"长方形周长: "<<(a+b)*2<<endl;
}
};
int main()
{
Rectangle r;
r.area();
r.perimeter();
}