C++_20_多态

发布于:2024-09-19 ⋅ 阅读:(113) ⋅ 点赞:(0)

多继承会造成 菱形继承** 使用虚继承来解决

不是给爷爷类加 也不是给子类加 是给父类加 虚基指针和虚基表

多态

概念:

概念: 一个事物的多种形态,简称多态

如:

  • 对象的多态

    ​ 张三

    ​ 在对象面前 怂

    ​ 在朋友面前 谄媚

    ​ 在父母面前 孝顺

  • 事的多态

    ​ 吃饭

    ​ 中国人用筷子

    ​ 美国人用刀叉

    ​ 印度人用手抓

  • 事务的多态

    • 上行: 子类对象换为父类对象
    • 下行 : 父类对象换为子类对象
  • 事的多态

    • 重载:
    • 重写:
    • 重定义:

物的多态:

上行:

特点: 自动转换 无风险

概念:子类对象转换为父类对象

语法:

子类对象 转换为 父类对象

  • 父类名 &父类对象名 = 子类对象;

子类对象指针 转换为 父类对象指针

  • 父类名 *父类对象指针 = 子类对象指针;

示例:

在这里插入图片描述

注意:

子类对象转换为父类对象或父类对象指针后,使用转换后父类对象或父类对象指针 无法使用子类特有的成员

包括 成员对象 和 成员函数

下行:

概念: 父类对象 转换 为 子类对象 父类对象指针 转换为 子类对象指针

特点: 有风险 需要强制转换 语法就带

语法:

子类名 &子类对象 = ( 子类名& )父类对象名;

  • Cat cat = (Cat &) anim; // Cat &强制转换

子类名 子类对象指针 = ( 子类名 * ) 父类对象指针名;

事的多态

重载

  • 同一个类中函数名相同,形参列表不同,称为重载

重写

  • 继承关系中,子类成员函数与父类成员函数函数名相同,形参列表相同,返回值类型相同

重定义

  • 函数名相同,即为重定义 c不允许重定义 C++允许

虚函数:

概念: 使用 virtual 修饰的函数

语法:

 virtual 返回值类型 函数名()
 {
     函数体;
 }

原理: 使用 虚基指针和虚基表

特定:

  • 当子类重写 父类 提供的 虚 函数

  • 当子类对象转换为父类对象 ,使用转换的父类对象调用 重写的虚函数,此时执行的子类重写后的

未使用 虚函数 重写父类的函数后 造成想要的效果出现不了

在这里插入图片描述

  • 发现打印的是A 不是想要的B

  • 解决方式
    

    虚函数: virtual 父类函数 加 virtual

#include <iostream>
using namespace std;
// 虚函数 解决 继承重写的问题
class A
{
public:
    virtual void method()
    {
        cout << " 父类 A" << endl;
    }
};

class B : public A
{
public:
    void method()
    {
        cout << " 子类 B" << endl;
    }
};
int main(int argc, char const *argv[])
{
    B b;
    A &a = b;   // 上行  将 b对象 转为 A 类对象
    a.method();
    return 0;
}
 //  有问题 没出预期效果 没出 B   应该出 B

在这里插入图片描述

  • 虚函数 是有函数体的 不知道才写纯虚 函数 知道就写虚函数 要是不知道函数体就写
    纯 虚函数 并子类重写 父类的所有纯虚函数 不然创建不了对象

纯虚函数:

  • 没有函数体
  • 如果一个类中有虚函数,该类无法直接创建对象,这种类称为抽象类
  • 子类继承于抽象类,要么重写所有纯虚函数,要么

概念:

  • 没有函数体的虚函数
  • 如果一个类中有纯虚函数,该类无法直接创建对象,这种类称为抽象类子类继承与抽象类,要么重写抽象类中所有的纯虚函数要么自己也是抽象类

语法:

virtua]返回值类型函数名(形参列表)= 0;

使用完 释放内存的时候 担心 内存释放的不干净

父类 anim 子类dog 释放dog 出现问题 出现 只释放了 anim 内存 而没释放 dog

释放 anim 就两者都释放掉了 但就是担心你释放的时候写错 忘记释放内存 使用虚析构造解决

在这里插入图片描述

在这里插入图片描述

#include <iostream>
using namespace std;
   					// 纯虚函数
   class A{
public:
virtual void me01() = 0 ; // 纯虚函数 1
   virtual void me02() = 0 ; // 纯虚函数 2 只有重写父类的纯虚函数之后才能创建对象
   };
   class B :public A{
 public:
 //重写父类所有纯虚函数  重写的不是全部的时候 就创建不了对象
        void me01()
        {
            cout<<"B 01"<<endl;
        }
        void me02()
        {
            cout<<"B 02"<<endl;
        }
   };
   int main(int argc, char const *argv[])
{
 B b;  //创建对象才正常   
 return 0;
   }

虚析构造:【*】

概念:

  • 使用 virtual 修饰的析构函数

特点:

  • 子类对象指针转换为父类对象指针,此时delete父类对象指针,只会调用父类析构函数
  • 如果父类析构函数为虚析构造,那么也将调用子类析构函数

语法: 【注意 是给父类中写 】

virtual ~父类名()
{
    
}

示例:

在这里插入图片描述

在这里插入图片描述

纯虚析构:【**】

优化虚析函数版的

因为要分文件 所以优化用这个

概念 : 没有函数体的虚析构造

语法 :

virtual ~父类名()= 0;

注意 :

  • 类外实现
  • 纯虚析构也是纯虚函数
  • 顾纯虚析构的类也是抽象类,此时无法创建对象

案例:

小张是个宠物医生

张女士 养了一只狗叫旺财

李女士 养了一只猫叫布丁

分析:

存在的对象

​ 小张 张女士 李女士 旺财 布丁

类:

​ 动物:人类 医生类 ​ 狗类 猫类

​ A 动物类:

​ 成员变量: name

​ 成员函数: 1 speak 2 无参构造 3 有参构造 4 拷贝构造 5 纯虚析构

​ B 人类:

​ 特有成员: 宠物 [anim]

​ 重写父类speak函数

​ 无参构造 有参构造 拷贝构造 纯虚析构

​ C 医生类:

​ 特有函数: work:治病

​ 无参构造

​ 有参构造

​ 拷贝构造

​ 纯虚析构

​ D 狗类

​ 重写父类speak函数

​ 无参构造

​ 有参构造

​ 拷贝构造

​ 纯虚析构

​E 猫类

​ 重写父类speak函数

​ 无参构造

​ 有参构造

​ 拷贝构造

​ 纯虚析构

​==============
创建对象

​ 建立关系

分文件编写:

头文件:

anim.h
#ifndef xx
#define xx
#include <iostream>
#include <stdlib.h>
#include <string.h>
class Anim
{
private:
    char *name;

public:
    Anim();
    Anim(char *name);
    Anim(const Anim &anim);
    virtual ~Anim();                    // 纯虚析构  virtual ~父类名()= 0;
    virtual void speak(char *info) = 0; // 纯虚函数 virtua]返回值类型函数名(形参列表)= 0;
    char *getName() const;
    void setName(char *name);
};
#endif
person.h
#ifndef tt
#define tt
#include <iostream>
#include "anim.h"
using namespace std;
class Person : public Anim
{
    private:
        Anim* anim;
    public:
        Person();
        Person(char *name);
        Person(char *name,Anim* anim);
        Person(const Person &p);
        ~Person() ; // 纯虚函数 virtua]返回值类型函数名(形参列表)= 0;
        Anim* getAnim() const;
        void setAnim(Anim*  anim);
        void speak(char *info);
};
#endif
doctor.h
#ifndef do
#define do
#include <iostream>
#include "person.h"
class Doctor : public Person
{
public:
    Doctor();
    Doctor(char *name);
    // virtual ~Doctor() = 0;
    ~Doctor();
    void work(Anim *anim);
};
#endif
dog.cpp
#ifndef dogg
#define dogg
#include <iostream>
#include "anim.h"
class Dog : public Anim
{
public:
    Dog();
    Dog(char *name);
    // virtual ~Dog() = 0;  使用这个有问题
    ~Dog();
    void speak(char *info);
};
#endif
cat.h
#ifndef catt
#define catt
#include <iostream>
#include "anim.h"
class Cat : public Anim
{
public:
    Cat();
    Cat(char *name);
    ~Cat();
    void speak(char *info);
};
#endif

源文件

anim.cpp
#include "anim.h"
Anim::Anim() : name(NULL) {};
Anim::Anim(char *name)
{
    int len = strlen(name);
    this->name = (char *)calloc(len + 1, 1);
    strcpy(this->name,name);
}
Anim::Anim(const Anim &anim)
{
    int len = strlen(anim.name);
    this->name = (char *)calloc(len + 1, 1);
    strcpy(this->name,anim.name);
}
Anim::~Anim()
{
    if (name != NULL)
    {
        free(name);
        name = NULL;
    }
}
char * Anim::getName() const
{
    return name;
}

void Anim::setName(char *name)
{
    if (this->name != NULL)
    {
        free (this->name);
    }
    int len = strlen(name);
    this->name = (char *)calloc(len + 1, 1);
    strcpy(this->name,name);
}
person.cpp
#include "person.h"
Person::Person() : anim(NULL) {}
Person::Person(char *name) : Anim(name), anim(NULL) {}
Person::Person(char *name, Anim *anim) : Anim(name), anim(anim) {}
Person::Person(const Person &person)
{
    // 因为形参 person 使用了const 修饰 意味着不能修改其成员
    // 此时使用person调用 其函数 系统担心 函数内部对其成员进行修改,
    // 顾调用 的函数必须是使用const 修饰的成员函数
    this->anim = person.getAnim(); 
    char *name = person.getName();  //加const
}
Person::~Person() {} // 纯虚析构
Anim *Person::getAnim() const
{
    return anim;
}
void Person::setAnim(Anim *anim)
{
    this->anim = anim;
}
void Person::speak(char *info)
{
    cout << this->getName() << " "<<endl;
}
doctor.cpp
#include "doctor.h"
Doctor::Doctor() {}
Doctor::Doctor(char *name) : Person(name) {}
Doctor::~Doctor() {}
// 给宠物看病  将宠物传进来
void Doctor::work(Anim *anim)
{
        cout << this->getName() << "给" << anim->getName() << "看看病!" << endl;
        anim->speak(NULL);
}
cat.cpp
#ifndef catt
#define catt
#include <iostream>
#include "anim.h"
class Cat : public Anim
{
public:
    Cat();
    Cat(char *name);
    ~Cat();
    void speak(char *info);
};
#endif
dog.cpp
#include "dog.h"
using namespace std;
Dog::Dog() {};
Dog::Dog(char *name) : Anim(name) {}
Dog::~Dog() {}
void Dog::speak(char *info)
{
    cout << getName() << ":" << "汪汪汪" << endl;
}

执行文件:

main.cpp
#include <iostream>
#include "anim.h"
#include "doctor.h"
#include "cat.h"
#include "dog.h"
#include "person.h"
using namespace std;
int main(int argc, char const *argv[])
{
    Doctor *d = new Doctor("小张");
    Dog *dog  = new Dog("旺财");
    Cat *cat =new Cat("大橘");
    Person* p1 = new Person("张女士",dog);
    Person* p2 = new Person("李女士",cat);
    d->work(p1->getAnim());
    d->work(p2->getAnim());
    return 0;
}

在这里插入图片描述


网站公告

今日签到

点亮在社区的每一天
去签到