目录
一、数据抽象
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;
}