C++复试第八篇:面向对象【数据抽象、继承、虚析构】+模板

目录

一、数据抽象

二、继承

三、多种继承

四、纯虚函数 与 抽象基类

 五、虚析构

六、模板


一、数据抽象

        1. ADT(抽象数据类型)

        抽象数据类型的基本思想是把数据定义为抽象的对象集合,只为它们定义可用的合法操作,并不暴露内部实现的具体细节分离类的实现与接口,保护类的成员不被随意访问的能力。

        一个数据类型的操作通常可以分为三类:

        构造操作:这些操作基于一些已知信息,产生出这种类型的一个新对象
        解析操作:这种操作从一个对象取得有用的信息,其结果反应了被操作对象的某方面特性,单结果并不是本类型的对象。
        变动操作:这类操作修改被操作对象的内部状态

二、继承

        1. 通过“ 继承 ”联系在一起的类构成一种层次关系,根部是基类,上面是派生类

                ● 基类负责定义在层次关系中所有类共同拥有的成员

                ● 派生类负责定义各自特有的成员

        

        2. 虚函数virtual:在基类内,希望各个派生类定义出不同版本的函数(覆盖),当我们使用指针引用调用virtual函数时,该调用将被动态绑定

       (1)构造函数静态函数都不能定义成虚函数。任何构造函数之外的非静态函数都可以定义为虚函数

        (2)虚函数的解析过程发生在运行时,普通函数的解析过程发生在编译

        (3)

                ● 基类:

class Quote{
public:
    std::string isbn() const;
    virtual double net_price(std::size_t n) const;
};

               ● 派生类,必须通过类派生列表(: ),说明是从哪个基类继承而来的

class Bulk_quote : public Quote{
    public:
        double net_price(std::size_t) const override;
};

       

        3. 动态绑定:用同一段代码处理基类和派生类的对象,函数的运行版本由传入的实参决定,且只有当我们通过 指针引用 调用虚函数时才会发生

       

        4. 多态性:程序能通过 指针引用 所绑定传入的实参获取类型特定行为的能力

        5.

        ● 访问运算符private、public,现在有了一个protected,是基类希望派生类可以访问,但其他对象不能访问

                所以派生类对象可以访问基类的public和protected成员                

         ● 不想被继承的类,后面加上 final

class NoDerived final{...}

        6. 存在 派生类 -> 基类的自动类型转换(由有到无) =   把派生类的对象当成基类对象来使用,

        (1) 不存在 基类 -> 派生类由无到有

        (2)且只对指针引用类型有效      

        (3) 派生类—>基类,可能会由于访问受限而不可行

Quote item; //基类对象
Bulk_quote bulk;//派生类对象

Quote *p = &item; //p是一个指向Quote的指针
p = &bulk;  //指针可以指向派生类对象的地址

Quote &r = bulk; //r也可以绑定到派生类对象的基类部分

        7. 派生类的基类部分必须得使用基类构造函数

三、多种继承

        1. 访问说明符:(1)基类中一个成员的权限  (2)派生类的派生列表中的访问说明

           ——private派生访问说明符,不影响派生类自己内部的访问权限,但是会限制派生类的用户(派生类)

class Base{
public:
    void pub_mem();
protected:
    int prot;
private:
    char priv;
};


//公有继承
struct Pub_Derv : public Base{
    int f(){return prot;}
//对!
};


//私有继承不印象派生类内部的访问权限
struct Priv_Derv : private Base{
    int f1() const {return prot;}

};


//错!是私有继承的派生类的派生类,成员都变成Private了
struct Derived : public Priv_Derv{
    int use_base() {return prot;}

};

        2. 类篇有提到:struct默认访问权限是public的(都有u),class默认访问权限是private

            继承也类似,使用struct默认公有继承class默认私有继承

四、纯虚函数 与 抽象基类

        1. 纯虚函数:只是一个通用概念,而非某种具体的函数,不需要定义,如果定义只能在类外

声明为纯虚函数的方法:   右侧“  =0  ” 

class Disc_quote : public Quote{
public:

    //构造函数
    Disc_quote() = default;
    Disc_quote(const std::string& book, double price, std::size_t qty,
                double disc):
                Quote(book,price),
                quantity(qty),discount(disc){}

protected:
    std::size_t quantity = 0;  //纯虚函数
    double discount = 0.0;
} 

       

        2. 含有纯虚函数的类是抽象基类,抽象基类负责定义接口口,不可以直接创建一个抽象基类的对象,只有覆盖了纯虚函数的它的派生类才能定义对象

 五、虚析构

  在基类中,我们要将析构函数(delete功能)定义成虚函数,以确保执行正确的析构函数版本

        1. 

哪种类需要虚析构函数?

          —— 基类需要虚析构函数。保证当我们删除一个基类指针,而该指针实际指向一个派生类对象时,程序也能正常运行

class Quote{
public:
    //动态绑定析构函数
    virtual ~Quote() = default;
};
#include <iostream>

class Base
{
public:
    Base(){ std::cout << "B-Constructor\n" ;}
    ~Base(){ std::cout << "B-Destructor\n";}

};

class Derived : public Base
{
public:
    Derived(){ std::cout << "D-Constructor\n" ;}
    ~Derived(){ std::cout << "D-Destructor\n";}

};


int main()
{
    Base* base = new Base();
    delete base;
    std::cout << "------------------\n";

    //建立一个Derived()派生类的对象,当做base指针处理
    Base* poly = new Derived();
    delete poly;
    
    return 0;
} 

        结果

B-con

B-des

 ----------------------

B-con

D-con

D-des     //没有标记virtual,造成了内存泄漏

B-des

六、模板

        1. 模板templates:只是一个公式,可以用来生成特定类型的函数

        以关键字template开始,后跟一个模板参数列表:template<参数a,参数b...>

#include <iostream>
#include <string>


//3个Print重载函数

void Print(int value)
{
    std::cout << value <<std::endl;
}

void Print(float value)
{
    std::cout << value <<std::endl;
}

void Print(std::string value)
{
    std::cout << value <<std::endl;
}

main()
{
    .... ....
}

#include <iostream>
#include <string>


//等价于:template<class T>
template<typename T>
void Print(T value)
{
    std::cout << value <<std::endl;
}


main()
{
    Print(5);//实际类型是编译器从实参读出来的,Print函数只有在调用时才会存在
    Print("hello");
    Print(5.5f);

    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值