多态(类)

多态

基本概念

多态性是指不同对象收到相同消息时会执行不同的操作。所谓消息是指对类的成员函数的调用,不同的行为是指不同的实现,也就是调用了不同的函数,即“一个接口、多种实现”。

多态的实现方式

多态的实现方式主要有:

(1)静态多态(重载,模板)

在编译的时候确定调用函数的类型。如在重载函数调用时,需要通过函数的参数列表来确认调用的函数。

(2)动态多态(覆盖,虚函数实现)

在运行的时候才确定调用的函数,运行基类指针指向派生类的对象,并调用派生类的函数。

运算符重载

可以对运算符进行重新定义,赋予运算符新的功能,使运算操作能够适应于自定义的类型。

插播一下,类可以直接进行整体赋值,会将成员变量的值依次进行赋值

运算符重载的两种形式:

  1. 成员函数

  2. 友元函数(全局函数)

代码示例如下:

#include<iostream>
#include<iomanip>
using namespace std;
class complex
{
public:
    complex(double x, double y) :real(x), img(y) {}
    friend  complex operator+(complex a, complex b);
    complex operator-(complex b);
    void display();
private:
    double real;
    double img;
};
complex complex::operator-(complex b)
{
    return complex(this->real - b.real, this->img - b.img);
}
complex operator+(complex a, complex b)
{
    return complex(a.real + b.real, a.img + b.img);
}
void complex::display()
{
    cout << real << ' ' << showpos << img <<' ' << 'i' << endl;
}
int main()
{
    complex a(2.5, 3.6);
    complex b(3.4, 8.2);
    complex c = a + b;
    complex d = a - b;
    c.display();
    d.display();
}

但在c++中也有不可以被重载的运算符:

1. 作用域解析运算符 (::)
用途:用于访问类的成员、命名空间的成员和全局变量。
原因:重载这个运算符会破坏 C++ 语言的基本语法规则。
2. 成员访问运算符 (.)
用途:用于访问对象的成员。
原因:重载这个运算符会改变对象成员访问的基本方式,可能导致代码的可读性和语法的混乱。
3. 成员指针访问运算符 (.* 和 ->*)
用途:用于通过成员指针访问类成员。
原因:这些运算符涉及到指针语法,重载会破坏语言的指针访问机制。
4. 条件运算符 (?:)
用途:条件表达式,根据条件返回不同的结果。
原因:重载这个运算符会使条件表达式的语法复杂化,难以理解和维护。
5. sizeof 运算符
用途:返回对象或类型的大小(字节数)。
原因:重载这个运算符会改变类型和对象的基本大小计算方式,破坏语言的基本特性。
6. typeid 运算符
用途:用于在运行时获取对象的类型信息。
原因:重载这个运算符会影响运行时类型识别机制,破坏 RTTI(Run-Time Type Information)的工作。
7. static_cast、dynamic_cast、const_cast、reinterpret_cast
用途:用于类型转换。
原因:这些运算符是 C++ 类型转换机制的一部分,重载它们会破坏类型安全和类型转换的基本语义

对于友元函数的理解:

首先了解友元:友元(friend)是一种机制,允许一个类或函数访问另一个类的私有或受保护成员。通过友元关系,类或函数可以绕过访问权限规则,直接访问被授权的类的私有成员。

其次友元函数的声明必须在函数的内部,友元函数的声明位置决定了它可以访问该类的私有和受保护成员。

设置了友元函数,在该函数中便可以访问相应的对象的私有区域的值与函数。

同时也可以设置为成员函数,成员函数也可以进行运算符重载的操作。(这样子也可以访问参数类中的私有区域的数据和函数)

虚函数

虚函数是实现c++多态的基础,通过基类访问派生类定义的函数实现多态。虚函数用virtual关键字说明,只能修饰非静态的成员函数,虚函数经过派生之后,就可以实现运行过程中的多态。

C++中引入了虚函数的机制在派生类中可以对基类中的成员函数进行覆盖(重定义,override)。

虚函数的声明形式:

virtual 返回值类型 函数名(形参表){

函数体

}

使用:在基类中运用虚函数,则在派生类中可以正确调用派生类的成员函数(与基类名字相同的函数)

Why需要虚函数?

为了可以正确调用基类与派生类中名字相同的函数。

虚析构函数

如果需要允许基类指针调用派生类对象的析构函数,就需要让基类的析构函数成为虚函数。

否则可能造成内存泄漏

virtual ~类名();

虚析构函数的作用主要是确保在删除指向派生类对象的基类指针时,能够正确地调用派生类的析构函数,从而避免内存泄漏和其他资源未被正确释放的问题

纯虚函数与抽象类

纯虚函数是一个在基类中声明的虚函数,声明格式为:

class 类名{

virtual 返回值类型 函数名(参数表) =0; //纯虚函数

...

};

带有纯虚函数的类称为抽象类,主要用于类的顶层设计,用于说明某一类型应该具有的功能或者操作,但其具体实现需要延迟到子类中

注意:抽象类只能作为基类来使用,不能声明抽象类的对象。构造函数不能是虚函数,析构函数可以是虚函数。

同时我们可以知道,我们可以用基类的指针指向派生类,(但应注意该指针只能访问派生对象从基类继承而来的那些成员)

所以我们可以运用一个函数就可以实现对基类所有派生类的访问,使用基类的指针就可以实现对派生类的部分访问,但应该注意一个问题,运用基类的指针时,如果派生类有与基类同名的函数,会发生什么?

(会调用基类的同名函数,而不是派生类,所以我们可以使用虚函数,来实现我们调用的是派生类的同名函数,而不是基类的同名函数)

总结:我们可以发现使用基类的指针,如果基类的函数没有使用virtual去修饰的话,在调用基类与派生类的同名函数中,会优先调用基类的同名函数,同时如果基类的指针也会优先调用基类的构造函数,如果基类指针指向的是派生类,在delete 该指针时,会优先调用基类的析构函数,而不是派生类。若基类的析构函数被virtual修饰后,二者的析构函数便会被同时调用了

下面采用多态写一份代码,来理解

#include<iostream>
#include<math.h>
using namespace std;
class shape
{
public:
    virtual double Area() = 0;
};
class sanjiao:public shape
{
private:
    double a;
    double b;
    double c;
    double p=(a+b+c)/2;
public:
    sanjiao(double a, double b,double c) :a(a),b(b),c(c){};
    double Area() { return sqrt(p*(p-a)*(p-c)*(p-b)); }
};
class yuan :public shape
{
private:
    double r;
public:
    yuan(double r) :r(r) {}
    double Area() { return r * r * 3.14; }
};
class changfang :public shape
{
private:
    double chang;
    double kuan;
public:
    changfang(double a, double b) :chang(a), kuan(b) {}
    double Area() { return kuan * chang; }
};
double sumarea(shape* shapes[], int size)
{
    double sum = 0;
    for (int i = 0; i < size; i++)
    {
        sum += shapes[i]->Area();
    }
    return sum;
}
int main()
{
    yuan a(2);//12.56
    changfang b(3, 4);//12
    sanjiao c(3,4,5);//6
    shape* shapes[] = { &a,&b,&c };
    cout << sumarea(shapes, 3);
    return 0;
}

模板与容器

模板

模板(template)是C++语言的一项重要技术,具有如下优势:

(1)代码重用的重要机制,是泛型技术(即与数据类型无关的通用程序设计技术)的基础;

(2)区分算法与数据类型,能够设计出独立于具体数据类型的模板程序;

(3)模板程序能以数据类型为参数生成针对于该类型的实际程序代码。

模板分为函数模板和类模板

函数模板:

template<class T1,class T2,…>

返回类型 函数名(参数列表){

}

其中,T1,T2,…是模板参数

注意:不允许template与函数模板定义之间有任何语句,包括空行。

类模板:

类模板是用于设计结构和成员函数完全相同,但所处理的数据类型不同的通用类。

类模板的定义形式为:

template<class T1, class T2,**…>**

class 类名{

};

返回值和参数类型以及类中的部分数据域均可以用T来定义。

容器

STL即标准模板,是基于模板技术的一个库,提供了模板化的通用数据结构、类和算法。这些数据结构和算法是准确而有效的,可以被直接用于系统实现,而不需要进行基础功能的测试,保证了系统的正确性和稳定性。

STL的核心内容包括容器、迭代器和算法。其中容器(container)是用于存储其他对象的对象,STL中容器包括:

(1)顺序容器:将相同数据类型对象的有限集按顺序组织在一起的容器,用来表示线性数据结构,如向量(vector)、链表(list)和双端队列(deque)。

(注意头文件的引入如<vector>)

(2)关联容器:非线性容器,根据键进行快速存储、检索数据的容器,如集合(set)、多重集合(multiset)、映射(map)和多重映射(multimap)。

迭代器(<iterator>)

函数名说明
begin()指向容器的起点,即第一个元素
end()指向容器的结束,结束点在最后一个元素之后
rbegin()指向按方向顺序的一个元素位置
rend()指向按反向顺序的最后一个位置

vector中的常用函数
  1. push_back(const T& value): 在数组末尾添加一个元素。

    • 参数: const T& value - 要添加到数组末尾的元素。

    • 返回值: 无。

  2. pop_back(): 移除数组末尾的元素。

    • 参数: 无。

    • 返回值: 无。

  3. clear(): 移除数组中的所有元素。

    • 参数: 无。

    • 返回值: 无。

  4. size(): 返回数组中元素的数量。

    • 参数: 无。

    • 返回值: size_type - 数组中元素的数量。

  5. empty(): 检查数组是否为空。

    • 参数: 无。

    • 返回值: bool - 如果数组为空则返回true,否则返回false

  6. at(size_type pos): 返回指定位置的元素,带有边界检查。

    • 参数: size_type pos - 要访问的元素的位置。

    • 返回值: T& - 指定位置的元素(带边界检查,会抛出std::out_of_range异常)。

  7. operator[] (size_type pos): 返回指定位置的元素,不带边界检查。

    • 参数: size_type pos - 要访问的元素的位置。

    • 返回值: T& - 指定位置的元素(不带边界检查)。

  8. front(): 返回数组的第一个元素。

    • 参数: 无。

    • 返回值: T& - 第一个元素。

  9. back(): 返回数组的最后一个元素。

    • 参数: 无。

    • 返回值: T& - 最后一个元素。

  10. begin(): 返回指向数组第一个元素的迭代器。

    • 参数: 无。

    • 返回值: iterator - 指向第一个元素的迭代器。

  11. end(): 返回指向数组末尾(最后一个元素的下一个位置)的迭代器。

    • 参数: 无。

    • 返回值: iterator - 指向末尾(最后一个元素的下一个位置)的迭代器。

  12. erase(iterator position): 移除指定位置的元素。

    • 参数: iterator position - 要移除的元素的位置。

    • 返回值: iterator - 指向被移除元素之后的元素的迭代器。

  13. erase(iterator first, iterator last): 移除指定范围内的元素。

    • 参数: iterator first - 要移除范围的起始位置。 iterator last - 要移除范围的结束位置。

    • 返回值: iterator - 指向被移除范围之后的元素的迭代器。

  14. insert(iterator position, const T& value): 在指定位置插入一个元素。

    • 参数: iterator position - 插入位置。 size_type count - 要插入的元素数量。 const T& value - 要插入的元素的值。

    • 返回值: iterator - 指向第一个新插入元素的迭代器。

  15. insert(iterator position, size_type count, const T& value): 在指定位置插入指定数量的元素。

    • 参数: iterator position - 插入位置。 size_type count - 要插入的元素数量。 const T& value - 要插入的元素的值。

    • 返回值: iterator - 指向第一个新插入元素的迭代器。

  16. insert(iterator position, InputIterator first, InputIterator last): 在指定位置插入另一个范围内的元素。

    • 参数: iterator position - 插入位置。 InputIterator first - 要插入元素范围的起始位置。 InputIterator last - 要插入元素范围的结束位置。

    • 返回值: iterator - 指向第一个新插入元素的迭代器。

  17. resize(size_type count): 调整数组的大小,使其包含指定数量的元素。

    • 参数: size_type count - 新的大小。

    • 返回值: 无。

  18. resize(size_type count, const T& value): 调整数组的大小,并用指定的值填充新添加的元素。

    • 参数: size_type count - 新的大小。 const T& value - 填充新元素的值。

    • 返回值: 无。

  19. swap(vector& other): 交换两个数组的内容。

    • 参数: vector& other - 与之交换内容的另一个vector

    • 返回值: 无。

stack和queue类似

算法

algorithm

算法(algorithm)是用模板技术实现的适用于各种容器的通用算法。算法一般通过迭代器间接地操作容器元素,而且通常返回迭代器作为算法运算的结果。

常用算法包括:find和count、search、merge、sort。

Sort的第三个参数可以是自己定义的比较函数,函数的返回值类型是bool类型,参数一般来说会含有两个,如果想要第一个参数在第二个之前就返回true,否则返回false

find与search的区别:

在C++中,find和search都是用于查找元素的方法,但它们的应用场景和实现方式有所不同。

  1. find:通常用于查找容器(如vector、list等)中的元素。它通过遍历容器中的每个元素,检查是否满足给定的条件(通常是与目标值相等)。如果找到满足条件的元素,find会返回该元素的迭代器;否则返回容器尾部的迭代器。find主要用于无序容器或有序容器中查找特定值的情况。

  2. search:通常用于在有序容器(如sorted_vector、set等)中查找一系列连续的元素。它使用二分查找算法,在有序容器中高效地查找给定的序列。search接受两个迭代器参数,分别表示要查找的序列的起始和结束位置。如果找到匹配的序列,search返回第一个匹配元素的迭代器;否则返回容器尾部的迭代器。

总结:find主要用于查找单个元素,适用于无序或有序容器;search主要用于查找连续的序列,适用于有序容器。

merge:合并两个有序的序列。

sort(a,b):排序,a表示起点,b是终点,从小到大进行排序。

  1. std::sort

    • 用法: 对范围内的元素进行排序。

    • 原型

      :

      cpp复制代码template<class RandomIt>
      void sort(RandomIt first, RandomIt last);
      ​
      template<class RandomIt, class Compare>
      void sort(RandomIt first, RandomIt last, Compare comp);
    • 参数

      :

      • RandomIt first: 要排序范围的起始迭代器。

      • RandomIt last: 要排序范围的结束迭代器。

      • Compare comp(可选): 自定义的比较函数对象。

    • 返回值: 无。

  2. std::find

    • 用法: 在范围内查找等于某个值的第一个元素。

    • 原型

      :

      cpp复制代码template<class InputIt, class T>
      InputIt find(InputIt first, InputIt last, const T& value);
    • 参数

      :

      • InputIt first: 查找范围的起始迭代器。

      • InputIt last: 查找范围的结束迭代器。

      • const T& value: 要查找的值。

    • 返回值: InputIt - 指向第一个等于value的元素的迭代器,如果未找到则返回last

  3. std::for_each

    • 用法: 对范围内的每个元素应用给定的函数。

    • 原型

      :

      cpp复制代码template<class InputIt, class UnaryFunction>
      UnaryFunction for_each(InputIt first, InputIt last, UnaryFunction f);
    • 参数

      :

      • InputIt first: 要操作范围的起始迭代器。

      • InputIt last: 要操作范围的结束迭代器。

      • UnaryFunction f: 要应用的函数对象。

    • 返回值: UnaryFunction - 经过应用的函数对象。

  4. std::transform

    • 用法: 对范围内的元素应用一个函数并将结果存储到另一个范围。

    • 原型

      :

      cpp复制代码template<class InputIt, class OutputIt, class UnaryOperation>
      OutputIt transform(InputIt first, InputIt last, OutputIt d_first, UnaryOperation unary_op);
      ​
      template<class InputIt1, class InputIt2, class OutputIt, class BinaryOperation>
      OutputIt transform(InputIt1 first1, InputIt1 last1, InputIt2 first2, OutputIt d_first, BinaryOperation binary_op);
    • 参数

      :

      • InputIt first, InputIt last: 输入范围的起始和结束迭代器。

      • OutputIt d_first: 输出范围的起始迭代器。

      • UnaryOperation unary_opBinaryOperation binary_op: 要应用的函数对象。

    • 返回值: OutputIt - 指向最后一个被写入元素之后的位置的迭代器。

  5. std::copy

    • 用法: 将范围内的元素复制到另一个范围。

    • 原型

      :

      cpp复制代码template<class InputIt, class OutputIt>
      OutputIt copy(InputIt first, InputIt last, OutputIt d_first);
    • 参数

      :

      • InputIt first, InputIt last: 输入范围的起始和结束迭代器。

      • OutputIt d_first: 目标范围的起始迭代器。

    • 返回值: OutputIt - 指向最后一个被复制元素之后的位置的迭代器。

  6. std::reverse

    • 用法: 反转范围内的元素顺序。

    • 原型

      :

      cpp复制代码template<class BidirIt>
      void reverse(BidirIt first, BidirIt last);
    • 参数

      :

      • BidirIt first: 要反转范围的起始迭代器。

      • BidirIt last: 要反转范围的结束迭代器。

    • 返回值: 无。

  7. std::accumulate

    • 用法: 计算范围内元素的累计总和。

    • 原型

      :

      cpp复制代码template<class InputIt, class T>
      T accumulate(InputIt first, InputIt last, T init);
      ​
      template<class InputIt, class T, class BinaryOperation>
      T accumulate(InputIt first, InputIt last, T init, BinaryOperation binary_op);
    • 参数

      :

      • InputIt first, InputIt last: 输入范围的起始和结束迭代器。

      • T init: 初始值。

      • BinaryOperation binary_op(可选): 用于累加的二元操作函数。

    • 返回值: T - 累计总和。

  8. std::remove

    • 用法: 移除范围内所有等于某个值的元素,并返回新的结束迭代器。

    • 原型

      :

      cpp复制代码template<class ForwardIt, class T>
      ForwardIt remove(ForwardIt first, ForwardIt last, const T& value);
    • 参数

      :

      • ForwardIt first, ForwardIt last: 输入范围的起始和结束迭代器。

      • const T& value: 要移除的值。

    • 返回值: ForwardIt - 新的结束迭代器。

  9. std::unique

    • 用法: 移除相邻的重复元素,并返回新的结束迭代器。

    • 原型

      :

      cpp复制代码template<class ForwardIt>
      ForwardIt unique(ForwardIt first, ForwardIt last);
      ​
      template<class ForwardIt, class BinaryPredicate>
      ForwardIt unique(ForwardIt first, ForwardIt last, BinaryPredicate p);
    • 参数

      :

      • ForwardIt first, ForwardIt last: 输入范围的起始和结束迭代器。

      • BinaryPredicate p(可选): 判断元素是否相等的二元谓词。

    • 返回值: ForwardIt - 新的结束迭代器。

  10. std::lower_bound

    • 用法: 在已排序范围内查找第一个不小于给定值的元素的位置。

    • 原型

      :

      cpp复制代码template<class ForwardIt, class T>
      ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value);
      ​
      template<class ForwardIt, class T, class Compare>
      ForwardIt lower_bound(ForwardIt first, ForwardIt last, const T& value, Compare comp);
    • 参数

      :

      • ForwardIt first, ForwardIt last: 输入范围的起始和结束迭代器。

      • const T& value: 要查找的值。

      • Compare comp(可选): 用于比较的函数对象。

    • 返回值: ForwardIt - 指向第一个不小于value的元素的迭代器。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值