纯虚函数和抽象类

纯虚函数和抽象类

定义

注意抽象类不能创建对象,但是可以定义一个指针

注意抽象类不能有任何成员结构, 成员函数必须协成纯虚函数,

virtual 返回值  函数名(参数列表)=0

 注意

  含有纯虚函数的类被称为抽象类。抽象类只能作为派生类的基类,不能定义对象,但可以定义指针。在派生类实现该纯虚函数后,定义抽象类对象的指针,并指向或引用子类对象。

1)在定义纯虚函数时,不能定义虚函数的实现部分;

2)在没有重新定义这种纯虚函数之前,是不能调用这种函数的。

  抽象类的唯一用途是为派生类提供基类,纯虚函数的作用是作为派生类中的成员函数的基础,并实现动态多态性。继承于抽象类的派生类如果不能实现基类中所有的纯虚函数,那么这个派生类也就成了抽象类。因为它继承了基类的抽象函数,只要含有纯虚函数的类就是抽象类。纯虚函数已经在抽象类中定义了这个方法的声明,其它类中只能按照这个接口去实现。

抽象类实例

计算图形面积

#include <iostream>

using namespace std;

// 重点
// 面向抽象类编程(面向一套预先定义好的接口编程)
// 解耦合。。模块的划分
class Figure // 抽象类
{
public:
    // 约定一个统一的界面(接口) 让子类使用,让子类必须去实现
    virtual void getArea() = 0; // 纯虚函数
protected:
private:
};

class Circle : public Figure {
public:
    Circle(int a, int b) {
        this->a = a;
        this->b = b;
    }

    virtual void getArea() {
        cout << "圆的面积\t" << 3.14 * a * a << endl;
    }

protected:
private:
    int a;
    int b;
};

class Sanjiao : public Figure {
public:
    Sanjiao(int a, int b) {
        this->a = a;
        this->b = b;
    }

    virtual void getArea() {
        cout << "三角形的面积\t" << a * b / 2 << endl;
    }

protected:
private:
    int a;
    int b;
};

class Squre : public Figure {
public:
    Squre(int a, int b) {
        this->a = a;
        this->b = b;
    }

    virtual void getArea() {
        cout << "四边形的面积\t" << a * b << endl;
    }

protected:
private:
    int a;
    int b;
};

void PlayObj(Figure *base) {
    base->getArea(); // 会发生多态
}

int main() {
    // Figure f1; // 抽象类不能被实例化
    Figure *base = NULL;
    Circle c1(1, 2);
    Squre sq(1, 2);
    Sanjiao s1(2, 4);


    PlayObj(&c1);
    PlayObj(&s1);
    PlayObj(&sq);

    return 0;
}
抽象类编程例子一

计算程序员工资

忘记了手动调用delete,让其调用析构函数比较好

第二个有点错误, 不能说是抽象类

#include <iostream>
using namespace std;

/*
 编写一个c++程序 计算程序员工资(programer)
        1要求:能计算出初级程序员工资(junior_programer),中级程序员(mid_programer),高级程序员(Adv_progreamer)
        2要求利用抽象类统一界面(方便程序拓展),比如新增 计算架构师architect的工资
*/

// 程序员抽象类
class programer
{
public:
    virtual void getSal() = 0; //  抽象类接口
};

// 初级程序员
class junior_programer: public programer
{
public:
    junior_programer(char *name, char *job, int sal) // 浅拷贝
    {
        this->name = name;
        this->job = job;
        this->sal = sal;
    }
    virtual void getSal() // 接口类实现
    {
        cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl;
    }
private:
    char *name;
    char *job;
    int sal;
};

// 中级程序员
class mid_programer: public programer
{
public:
    mid_programer(char *name, char *job, int sal) // 浅拷贝
    {
        this->name = name;
        this->job = job;
        this->sal = sal;
    }
    virtual void getSal() // 接口类实现
    {
        cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl;
    }
private:
    char *name;
    char *job;
    int sal;
};

// 高级程序员
class Adv_programer: public programer
{
public:
    Adv_programer(char *name, char *job, int sal) // 浅拷贝
    {
        this->name = name;
        this->job = job;
        this->sal = sal;
    }
    virtual void getSal() // 接口类实现
    {
        cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl;
    }
private:
    char *name;
    char *job;
    int sal;
};

// 后来增加的 架构师类
class architect: public programer
{
public:
    architect(char *name, char *job, int sal) // 浅拷贝
    {
        this->name = name;
        this->job = job;
        this->sal = sal;
    }
    virtual void getSal() // 接口类实现
    {
        cout << "name = " << name << "\tjob = " << job << "\tsal = " << sal << endl;
    }
private:
    char *name;
    char *job;
    int sal;
};

// 计算函数,简单框架
void jisuan(programer *base)
{
    base->getSal();
}

// 引用
void jisuan(programer &base)
{
    base.getSal();
}
int main()
{
    junior_programer junior("张三", "初级", 5000);
    mid_programer    mid("李四",    "中级", 10000);
    Adv_programer    adv("王五",    "高级", 15000);

    // 系统扩展 增加代码 架构师工资
    architect arc("康总", "架构师", 30000);


    jisuan(&junior);
    jisuan(&mid);
    jisuan(&adv);

    jisuan(&arc);

    cout << endl;


    // 引用类型
    auto &i = junior;
    auto &j = mid;
    auto &k = adv;
    auto &l = arc;

    jisuan(i);
    jisuan(j);
    jisuan(k);
    jisuan(l);

    return 0;
}
别人的的方式
//编写一个c++程序 计算程序员工资(programer)
//1要求:能计算出初级程序员工资(junior_programer),中级程序员(mid_programer),高级程序员(Adv_progreamer)
//2要求利用抽象类统一界面(方便程序拓展),比如新增 计算架构师architect的工资

#include <iostream>
#include <cstring>

using namespace std;

// 定义程序员类, 抽象类
class Programer {
    virtual double getSal() = 0;
};

class Junior : Programer {
public:
    Junior(char *name = NULL, char *job = NULL, double sal = 7000) {

        auto len = strlen(name);
        this->name = new char[len + 1];
        strcpy(this->name, name);

        len = strlen(job);
        this->job = new char[len + 1];
        strcpy(this->job, job);
        this->sal = sal;

    }

    virtual ~Junior() {
        delete[]name;
        delete[]job;
        sal = 0;
        name = NULL;
        job = NULL;
        cout << "j" << endl;
    }

    virtual double getSal() {
        cout << this->name << " : " << this->job << ": " << this->sal << endl;
    }

public:
    char *name;
    char *job;
    double sal;
};

class Mid : public Junior {
public:
    Mid(char *name = NULL, char *job = NULL, double sal = 10000)
            : Junior(name, job, sal) {

    }

    virtual ~Mid()  // 会默认调用父类的析构函数
    {
        cout << "m" << endl;
    }
};

// 高级的
class Adv : public Junior {
public:
    Adv(char *name = NULL, char *job = NULL, double sal = 10000)
            : Junior(name, job, sal) {

    }

    virtual ~Adv()  // 会默认调用父类的析构函数
    {
        cout << "Adv" << endl;
    }
};

void print(Junior &obj) {
    obj.getSal();
}


int main() {
    Junior j("张三", "初级", 5000);
    Mid m("李四", "中级", 10000);
    Adv a("王五", "高级", 15000);
    print(j);
    print(m);
    print(a);

    return 0;
}
自己的另一种写法

抽象类编程

动物园类

#if 0
// main.cpp
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
#include "Animal.h"
#include "Dog.h"
#include "Cat.h"
#include "Dog.cpp"
#include "Cat.cpp"
#include "Animal.cpp"


using namespace std;

int main(void)
{
    letAnimalCry(new Dog);

    letAnimalCry(new Cat);

#if 0
    Animal *dog = new Dog;
    letAnimalCry(dog);
    delete Dog;
#endif

    return 0;
}
#endif

// --  Animal.h
#if 0
#pragma once
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>
using namespace std;

class Animal
{
public:
    //纯虚函数,让子类继承并且实现
    virtual void voice() = 0;
    Animal();
    virtual ~Animal();
};
//架构函数
//让动物叫
void letAnimalCry(Animal *animal);
#endif
// Animal.cpp
#if 0
#include "Animal.h"

inline
Animal::Animal()
{
    cout << "animal().." << endl;
}
inline
Animal::~Animal()
{
    cout << "~Animal()..." << endl;
}
inline
void letAnimalCry(Animal *animal)
{
    animal->voice();

    // 需要手动调用delete 让其调用析构函数
    if (animal != NULL) {
        delete animal;
    }
}
#endif

// Dog.h------------------------
#if 0
#pragma once
#include "Animal.h"
class Dog : public Animal
{
public:
    Dog();
    ~Dog();

    virtual void voice();
};
#endif

// Dog.cpp
#if 0
#include "Dog.h"

inline
Dog::Dog()
{
    cout << "Dog().." << endl;
}

inline
Dog::~Dog()
{
    cout << "~Dog().." << endl;
}
inline
void Dog::voice()
{
    cout << "狗开始哭了, 555" << endl;
}
#endif

// Cat.h
#if 0
#pragma once
#include "Animal.h"


class Cat : public Animal
{
public:
    Cat();
    ~Cat();

    virtual void voice();
};
#endif
// Cat.cpp
#if 0
#include "Cat.h"

inline
Cat::Cat()
{
    cout << "cat().." << endl;

}

inline
Cat::~Cat()
{
    cout << "~cat().." << endl;

}
inline
void Cat::voice()
{
    cout << "小猫开始哭了,66666" << endl;
}
#endif
动物园

电脑类实例:

#define _CRT_SECURE_NO_WARNINGS

#include <iostream>


using namespace std;

//--------  抽象层---------
//抽象CPU类
class CPU {
public:
//    CPU();

    virtual void caculate() = 0;
};

//抽象的card类
class Card {
public:
    virtual void display() = 0;
};

//抽象的内存类
class Memory {
public:
    virtual void storage() = 0;
};

//架构类
class Computer {
public:
    Computer(CPU *cpu, Card *card, Memory *mem) {
        this->cpu = cpu;
        this->card = card;
        this->mem = mem;
    }

    void work() {
        this->cpu->caculate();
        this->card->display();
        this->mem->storage();
    }

    ~Computer() {
        if (this->cpu != NULL) {
            cout << "~cpu" << endl;
            delete this->cpu;
        }
        if (this->card != NULL) {
            cout << "~card"<<endl;
            delete this->card;
        }
        if (this->mem != NULL) {
            cout << "~mem"<<endl;
            delete this->mem;
        }
    }

private:
    CPU *cpu;
    Card *card;
    Memory *mem;
};
// --------------------------

//-----------实现层----------
//具体的IntelCPU
class IntelCPU : public CPU {
public:
    virtual void caculate() {
        cout << "Intel CPU开始计算了" << endl;
    }
};

class IntelCard : public Card {
public:
    virtual void display() {
        cout << "Intel Card开始显示了" << endl;

    }
};

class IntelMem : public Memory {
public:
    virtual void storage() {
        cout << "Intel mem开始存储了" << endl;

    }
};

class NvidiaCard : public Card {
public:
    virtual void display() {
        cout << "Nvidia 显卡开始显示了" << endl;
    }
};

class KingstonMem : public Memory {
public:
    virtual void storage() {
        cout << "KingstonMem 开始存储了" << endl;
    }
};

//--------------------------

void test()
{
    Computer *com1 = new Computer(new IntelCPU, new IntelCard, new IntelMem);
    com1->work();
    delete com1;    // 如果定义一个指针不要忘记释放

}

//--------业务层-------------------
int main() {
    //1 组装第一台intel系列的电脑
#if 0
    CPU *intelCpu = new IntelCPU;
    Card *intelCard = new IntelCard;
    Memory *intelMem = new IntelMem;

    Computer *com1 = new Computer(intelCpu, intelCard, intelMem);

    com1->work();

    Card *nCard = new NvidiaCard;
    Memory* kMem = new KingstonMem;

    Computer *com2 = new Computer(intelCpu, nCard, kMem);

    com2->work();

    delete intelCpu;
#endif
//    Computer *com1 = new Computer(new IntelCPU, new IntelCard, new IntelMem);
//    com1->work();
//    delete com1;   // 这里不要忘记释放
    test();
    return 0;
}
这个好好看看

 圆类

#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;


//抽象的图形类
class Shape
{
public:
    //打印出图形的基本你属性
    virtual void show() = 0;
    //得到图形的面积
    virtual double getArea() = 0;

    virtual ~Shape() {

    }
};

//圆类
class Circle :public Shape
{
public:
    Circle(double r) {
        this->r = r;
    }

    //打印出图形的基本你属性
    virtual void show()  {
        cout << "圆的半径是 " << r << endl;
    }
    //得到图形的面积
    virtual double getArea()  {
        cout << "获取圆的面积" << endl;
        return this->r*this->r *3.14;
    }
    ~Circle() {
        cout << "圆的析构函数。。" << endl;
    }
private:
    double r;
};

class Square :public Shape
{
public:
    Square(double a) {
        this->a = a;
    }

    //打印出图形的基本你属性
    virtual void show() {
        cout << "正方形的边长是" << this->a << endl;
    }
    //得到图形的面积
    virtual double getArea() {
        cout << "得到正方形的面积" << endl;
        return a*a;
    }


    ~Square() {
        cout << "正方形的析构函数" << endl;
    }
private:
    double a;
};



int main(void)
{
    Shape *array[2] = { 0 };

    for (int i = 0; i < 2; i++) {
        //生成一个圆
        if (i == 0) {
            double r;
            cout << "请输入圆的半径" << endl;
            cin >> r;
            array[i] = new Circle(r);
        }
        //生成一个正方形
        else {
            double a;
            cout << "请输入正方形的边长" << endl;
            cin >> a;
            array[i] = new Square(a);
        }
    }


    //遍历这个array数组
    for (int i = 0; i < 2; i++) {
        array[i]->show();
        cout << array[i]->getArea() << endl;

        delete array[i];
    }

    return 0;
}
圆类

比较大的例子,推荐看看

多态练习, 企业信息管理

https://i.cnblogs.com/Files.aspx 

 函数指针与多态

函数指针基础

#include <cstdio>
#include <cstdlib>
#include <cstring>

// 数组类型, 基本语法知识梳理

// 定义一个数组类型
// int arr[10];

// 定义一个指针数组类型

// 定义一个指向 数组类型的指针, 数组类的指针
int main() {
    int a[10];  // a代表数组首元素地址, &a 代表整个数组的地址
    // a+1 代表步长加4个单元,就是a[1]的地址,
    // &a+1 代表步长加40个单元后的地址

    //
    {
        // 定义数组类型
        typedef int (myTypeArr)[10];
        myTypeArr myArr;
        myArr[0] = 10;
        printf("%d\n", myArr[0]);
    }

    {
        // 定义一个指针数组类型
        typedef int (*PTypeArray)[10]; // int * p
        PTypeArray myPArray;  // sizeof(int) * 10; 步长, myPArray 是一个二级指针

        myPArray = &a;
        // 相当于
        // int b = 10;
        // int *c = NULL;
        // c = &b;

        (*myPArray)[0] = 20;  // 注意这里
        printf("%d\n", a[0]);
    }

    {
        // 定义一个指向 数组类型的指针, 数组类的指针

        int (*MyPoint)[10]; // 告诉c编译器给我分配内存
        MyPoint = &a;

        (*MyPoint)[0] = 40;

        printf("%d\n", a[0]);

    }
    return 0;
}

// 函数指针语法知识梳理
// 如何定义一个函数类型
// 如何定义一个函数指针类型
// 如何定义一个函数指针(指向一个函数入口地址)

int add(int a, int b) {
    printf("func add...\n");
    return a + b;
}

int main01() {
    add(1, 2); // 直接调用// 函数名就是函数入口地址

    // 如何定义一个函数类型
    {
        typedef int (myFuncType)(int a, int b); // 定义一个类型
        myFuncType *myFuncTypePoint = NULL; // 定义了一个指针,指向某一种类的函数

        myFuncTypePoint = &add; // 细节,这里的&add &可以不加
        myFuncTypePoint(1, 2);  // 间接调用
    }

    // 定义一个函数指针类型
    {
        typedef int (*MyPointFuncType)(int a, int b); // int *a = NULL;
        MyPointFuncType myPointFunc = NULL; // 定义一个指针
        myPointFunc = add;
        myPointFunc(1, 2);
    }

    // 函数指针
    {
        int (*myPointFunc)(int a, int b); // 定义一个变量
        myPointFunc = add;
        myPointFunc(1, 2);
    }

}
函数指针基础
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int myAdd(int a, int b)
{
    printf("func myAdd...\n");
    return a + b;
}
int myAdd2(int a, int b)   // 相当于虚函数表
{
    printf("func myAdd2...\n");
    return a + b;
}

// 定义了一个类型
typedef int (*myTypeFuncAdd)(int a, int b);


// mainop都是函数指针做函数参数
int mainop(myTypeFuncAdd myFuncAdd)
{
    int c = myFuncAdd(1, 2); // 间接调用
    printf("mainop\n");

    return c;
}
// int (*myTypeFuncAdd)(int a, int b);  定义一个指向某种函数的指针
int mainop2(int (*myTypeFuncAdd)(int a, int b))
{
    int c = myTypeFuncAdd(1, 2);  // 间接调用
    printf("mainop2\n");

    return c;
}

// 间接调用
// 任务的调用,和任务的编写可以分开
int main()
{
    /*
    myTypeFuncAdd myfuncAdd = myAdd;

    myfuncAdd(1, 3);  // 直接调用

    mainop(myAdd);
    mainop2(myAdd);
    */

    mainop(myAdd);
    mainop(myAdd2);  // 相当于发生了多态,函数指针做函数参数
    return 0;
}
函数指针做函数参数思想
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;

int func(int a, int b)
{
    cout << " 1999 年写的 func" << endl;

    return 0;
}

int func2(int a, int b)
{
    cout << "1999 写的 func2" << endl;
    return 0;
}

int func3(int a, int b) 
{
    cout << "1999年 写的 func3 " << endl;
    return 0;
}

//2018想添加一个新的子业务
int new_func4(int a, int b)
{
    cout << "2018 新写的子业务" << endl;
    cout << "a = " << a << ", b = " << b << endl;
    return 0;
}

//方法一:  函数的返回值, 函数的参数列表(形参的个数,类型,顺序)
//定义一个函数类型。

typedef int(FUNC)(int, int);

//方法二:   定义一个函数指针
typedef int(*FUNC_P)(int, int);


//定义一个统一的接口 将他们全部调用起来。

void my_funtion(int(*fp)(int, int), int a, int b)
{
    cout << "1999年实现这个架构业务" << endl;
    cout << "固定业务1" << endl;
    cout << "固定业务2" << endl;

    fp(a, b);//可变的业务

    cout << "固定业务3" << endl;

}

int main(void)
{
#if 0
    //方法一:
    FUNC *fp = NULL;

    fp = func;
    fp(10, 20);

    FUNC_P fp2 = NULL;

    fp2 = func;

    fp2(100, 200);

    //方法三:
    int(*fp3)(int, int)   = NULL;
    fp3 = func;
    fp3(1000, 3000);
#endif
    my_funtion(func, 10, 20);
    my_funtion(func2, 100, 200);
    my_funtion(func3, 1000, 2000);

    my_funtion(new_func4, 2000, 3000);
    
    return 0;
}
函数指针的工程意义
#define _CRT_SECURE_NO_WARNINGS
#include <iostream>


using namespace std;
//-------------抽象层------------
//定义拆开锦囊方法的类型。
typedef void(TIPS)(void);

//定义锦囊
struct tip
{
    char from[64]; //谁写的
    char to[64];//写给谁的。
    //锦囊的内容
    TIPS *tp;//相当于抽象类的 纯虚函数.
};

//需要一个打开锦囊的架构函数
void open_tips(struct tip *tip_p)
{
    cout << "打开了锦囊" << endl;
    cout << "此锦囊是由" << tip_p->from << "写给 " << tip_p->to << "的。" << endl;
    cout << "内容是" << endl;
    tip_p->tp(); //此时就发生了多态现象。
}

//提供一个创建一个锦囊的方法
struct tip* create_tip(char*from, char *to, TIPS*tp)
{
    struct tip *temp = (struct tip*)malloc(sizeof(struct tip));
    if (temp == NULL) {
        return NULL;
    }
    strcpy(temp->from, from);
    strcpy(temp->to, to);
    //给一个回调函数赋值, 一般称 注册回调函数
    temp->tp = tp;

    return temp;
}

//提供一个销毁锦囊的方法
void destory_tip(struct tip *tp)
{
    if (tp != NULL) {
        free(tp);
        tp = NULL;
    }
}


// ------------- 实现层------------
//诸葛亮写了3个锦囊
void tip1_func(void)
{
    cout << "一到东吴就拜会乔国老" << endl;
}

void tip2_func(void)
{
    cout << "如果主公乐不思蜀,就谎称曹贼来袭。赶紧回来 " << endl;
}

void tip3_func(void)
{
    cout << "如果被孙权追杀,向孙尚香求救" << endl;
}

void tip4_func(void)
{
    cout << "如果求救孙尚香都不灵,  你们去死了, 我是蜀国老大了" << endl;
}


//---------------  业务层-----------------
int main(void)
{
    //创建出3个锦囊
    struct tip *tip1 = create_tip("孔明", "赵云", tip1_func);
    struct tip *tip2 = create_tip("孔明", "赵云", tip2_func);
    struct tip *tip3 = create_tip("孔明", "赵云", tip3_func);
    struct tip *tip4 = create_tip("庞统", "赵云", tip4_func);

    //由赵云进行拆锦囊。
    cout << "刚刚来到东吴, 赵云打开第一个锦囊" << endl;
    open_tips(tip1);
    cout << "-----------" << endl;

    cout << "刘备乐不思蜀, 赵云打开第二个锦囊" << endl;
    open_tips(tip2);
    cout << "-----------" << endl;

    cout << "孙权大军追杀,赵云打开第三个锦囊" << endl;
    open_tips(tip3);
    cout << "-----------" << endl;

    cout << "赵云发现,实在是杀不动了, 打开了第四个锦囊" << endl;
    open_tips(tip4);

    destory_tip(tip1);
    destory_tip(tip2);
    destory_tip(tip3);
    destory_tip(tip4);
    
    return 0;
}
诸葛亮锦囊妙计

未完待续....

猜你喜欢

转载自www.cnblogs.com/xiaokang01/p/9170248.html