• c++多态


    多态:是指有多种形态

     

    多态有两大类:

    1.静态多态:函数重载,运算符重载,复用函数名(编译阶段确定地址)

    2.动态多态:子类和虚函数实现运行时的多态(运行阶段确定地址)

    细分以下多态:

    1. 参数多态(函数模板和类模板)
    2. 包含多态  (virtual)
    3. 重载多态(重载多态是指函数名相同,但函数的参数个数或者类型不同的函数构成多态)
    4. 强制多态(强制类型转换)
    其中:
    1. 类型参数化多态和包含多态统称为一般多态性
    2. 重载多态和强制多态统称为特殊多态性

    静态多态(编译阶段提前标定,当父类指针或引用接收之类对象时)会在编译阶段提前绑定父类中的函数

    1. class A
    2. {
    3. public:
    4. void show(){cout << "父类show()" << endl;}
    5. };
    6. class B :public A
    7. {
    8. public:
    9. void show(){cout << "子类show()" << endl;}
    10. };
    11. //父类引用可以接受子类对象
    12. void show1(A &a)
    13. {
    14. a.show();
    15. }
    16. //父类指针接收子类对象
    17. void show2(A*p)
    18. {
    19. p->show();
    20. }
    21. int main()
    22. {
    23. B b;
    24. //结果输出 父类的show 因为编译阶段 show1函数提早绑定了父类地址
    25. show1(b);
    26. B *b1 = new B;
    27. //结果输出 父类的show 因为编译阶段 show1函数提早绑定了父类地址
    28. show2(b1);
    29. return 0;
    30. }

     在这里我们发现,我声明的时一个子类对象,但有父类指针或引用去接收时,调用的函数却是父类的,为了解决这个问题,c++提供了虚函数的概念。

    虚函数:

    虚函数 是在基类中使用关键字  virtual 声明的函数,在派生类中重写这个函数,当父类指针(引用)接收子类对象时,会采用动态多态,在运行阶段确定地址,会使用子类的函数
    子类重写父类虚函数时:子类的virtual可加可不加

    动态多态:

    1. class A
    2. {
    3. public:
    4. virtual void show(){cout << "父类show()" << endl;}//声明为虚函数
    5. };
    6. class B :public A
    7. {
    8. public:
    9. void show(){cout << "子类show()" << endl;}
    10. };
    11. //父类引用接受子类对象
    12. void show1(A &a)
    13. {
    14. a.show();
    15. }
    16. //父类指针接收子类对象
    17. void show2(A*p)
    18. {
    19. p->show();
    20. }
    21. int main()
    22. {
    23. B b;
    24. //结果输出 子类的show 因为运行阶段 show1函数最后绑定了父类地址
    25. show1(b);
    26. B *b1 = new B;
    27. //结果输出 子类的show 因为运行阶段 show1函数最后绑定了父类地址
    28. show2(b1);
    29. return 0;
    30. }

     C++提供多态的目的是:可以通过基类指针对所有派生类(包括直接派生和间接派生)的成员变量和成员函数进行“全方位”的访问,尤其是成员函数。如果没有多态,我们只能访问成员变量。

    纯虚函数:是一个在基类中声明的虚函数,在类中没有定义具体的操作内容。

    格式:

    virtual 函数类型 函数名(参数)=0;

    声明为纯虚函数,则该函数可以不用实现 (也可以实现),拥有纯虚函数的类也称为 抽象类

    1.抽象类不能实例化,但可以定义一个抽象类 指针和引用

    2.子类一般需要重写抽象类的纯虚函数,不然也成抽象类

    1. class person
    2. {
    3. public:
    4. //纯虚函数
    5. virtual void show() = 0;
    6. int age;
    7. };
    8. class son:public person
    9. {
    10. public:
    11. //重写父类的纯虚函数 子类未重写的话也为抽象类
    12. void show()
    13. {
    14. age = 20;
    15. cout << "son中age的值" << this->age << endl;
    16. }
    17. };
    18. int main()
    19. {
    20. //纯虚函数不能实例化
    21. //person p;//报错
    22. //但可以使用指针和引用
    23. //vector 为容器,类似数组
    24. vector<person*>p;
    25. vector<person&>p1;
    26. //非纯虚函数可以实例化
    27. son s;
    28. return 0;
    29. }

    什么样的函数不能声明为虚函数?

    1. 不能被继承的函数。
    2. 不能被重写的函数。
    3. 普通函数,友元函数,构造函数,内联成员函数,静态成员函数

    1)普通函数

    普通函数不属于成员函数,是不能被继承的。普通函数只能被重载,不能被重写,因此声明为虚函数没有意义。因为编译器会在编译时绑定函数。

    而多态体现在运行时绑定。通常通过基类指针指向子类对象实现多态。

    2)友元函数

    友元函数不属于类的成员函数,不能被继承。对于没有继承特性的函数没有虚函数的说法。

    3)构造函数

    首先说下什么是构造函数,构造函数是用来初始化对象的。假如子类可以继承基类构造函数,那么子类对象的构造将使用基类的构造函数,而基类构造函数并不知道子类的有什么成员,显然是不符合语义的。从另外一个角度来讲,多态是通过基类指针指向子类对象来实现多态的,在对象构造之前并没有对象产生,因此无法使用多态特性,这是矛盾的。因此构造函数不允许继承。

    4)内联成员函数

    我们需要知道内联函数就是为了在代码中直接展开,减少函数调用花费的代价。也就是说内联函数是在编译时展开的。而虚函数是为了实现多态,是在运行时绑定的。因此显然内联函数和多态的特性相违背。

    5)静态成员函数

    首先静态成员函数理论是可继承的。但是静态成员函数是编译时确定的,无法动态绑定,不支持多态,因此不能被重写,也就不能被声明为虚函数。

    虚析构和纯虚析构:

    1. 虚析构是把析构函数设置为虚函数,纯虚析构的话,是把析构函数弄成纯虚函数
    2. 虚析构和纯虚析构都需要实现
    3. 纯虚析构在类内声明,类外实现
    当子类开辟到堆区时,父类指针释放时无法调用子类析构代码
    虚析构的作用:当父类指针(或引用)接收子类在堆区生成的对象时,父类可以调用子类的析构函数

    当父类析构不是虚析构时:(delete 父类指针时不会调用子类的析构函数)

    1. class person
    2. {
    3. public:
    4. person()
    5. {
    6. cout << "person的构造函数" << endl;
    7. }
    8. //纯虚函数
    9. virtual void show() = 0;
    10. //析构
    11. ~person()
    12. {
    13. cout << "person的析构函数" << endl;
    14. }
    15. };
    16. class son :public person
    17. {
    18. public:
    19. son(int a)
    20. {
    21. age = new int(a);
    22. cout << "son的构造函数" << endl;
    23. }
    24. //重写父类的纯虚函数 子类未重写的话也为抽象类
    25. void show()
    26. {
    27. cout << "son中age的值" << this->age << endl;
    28. }
    29. ~son()
    30. {
    31. if (age != NULL)
    32. {
    33. delete age;
    34. age = NULL;
    35. }
    36. cout << "son的析构函数" << endl;
    37. }
    38. int* age;
    39. };

     把父类析构函数设置为虚析构时:

    1. //虚析构
    2. virtual ~person()
    3. {
    4. cout << "person的析构函数" << endl;
    5. }

     把父类析构函数设置为纯虚析构时:

    1. //纯虚析构 类内声明
    2. virtual ~person() = 0;
    3. //类外实现
    4. person::~person()
    5. {
    6. cout << "person的纯虚析构函数" << endl;
    7. }

    正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消正在上传…重新上传取消

    虚函数和纯虚函数的权限:

    1. 虚函数可以为private,并且可以被子类覆盖(因为虚函数表的传递),但子类不能调用父类的private虚函数。虚函数的重载性和它声明的权限无关。
    2. virtual修饰符则强调父类的成员函数可以在子类中被重写,因为重写之时并没有与父类发生任何的调用关系,故而重写是被允许的。
    3. 纯虚函数可以设计成私有的,不过这样不允许在本类之外的非友元函数中直接调用它,子类中只有覆盖这种纯虚函数的义务,却没有调用它的权利。
    1. class person
    2. {
    3. public:
    4. private:
    5. virtual void show()
    6. {
    7. cout << "父类的show()函数" << endl;
    8. }
    9. };
    10. class son :public person
    11. {
    12. public:
    13. void show()
    14. {
    15. cout << "子类的show()函数" << endl;
    16. }
    17. };
    18. int main()
    19. {
    20. son s;
    21. s.person::show();//子类无法访问父类的私有成员
    22. return 0;
    23. }

    运算符重载:

    运算符重载:是对已有的运算符赋予多重定义,使用同一个运算符用于不同类型的数据有不一样的解决方法

    c++规定: =    [ ]   ()  ->  这四个运算符只能被重载为类的非静态成员函数重载

    其他的可以被友元重载

    解释:

    其他运算符重载函数都会更具参数类型或数目进行精确匹配,

    这4个不具有这总检查功能,使用友元定义就会出错

    不能被重载的运算符: 

    sizeof      : ?      .      ::

    长度运算符     三目运算符     成员选择符    域解析符

    运算符重载的关键词:operator 

    运算符重载规则:

    1. 只能重载C++已有的运算符
    2. 重载的功能应该与原有功能相似(一般不要 重载 + 号用 - 号的作用)
    3. 重载子后,优先级和结合性不变 

    以下是重载运算符的示例:

    +号的重载(-号和+号类似)

    成员函数:
    1. person operator+(const person &p)
    2. {
    3. this->age += p.age;
    4. this->height += p.height;
    5. return *this;
    6. }
    7. int age;
    8. int height;

    全局函数:

    1. person operator+(const person &p,const person &p1)
    2. {
    3. person p2;
    4. p2.age = p.age + p1.age;
    5. p2.height = p.height + p1.height;
    6. return p2;
    7. }

    想要实现连续运算:可以返回类的引用即可实现

    全局函数: 

    1. person& operator+(const person &p,const person &p1)
    2. {
    3. person p2;
    4. p2.age = p.age + p1.age;
    5. p2.height = p.height + p1.height;
    6. return p2;
    7. }

     ++重载:(--和++类似)

    前置++:++x

    1. person& operator++()
    2. {
    3. age++;
    4. height++;
    5. return *this;
    6. }
    7. int age;
    8. int height;

    后置++:x++

    1. //int为占位参数用来区分 前置++和后置++
    2. person& operator++(int)
    3. {
    4. person p = *this;
    5. age++;
    6. height++;
    7. return p;
    8. }

     重载<<运算符:

    一般用全局函数实现,成员函数难以实现

    cout 的类为 ostream 输出流类

    cin   的类为  istream  输出流类

    1. class person
    2. {
    3. public:
    4. //有参构造
    5. person(int a,string b):age(a),name(b){}
    6. int age;
    7. string name;
    8. };
    9. //全局函数重载<<
    10. ostream& operator<<(ostream& o,const person &p1)
    11. {
    12. cout << "年龄为:" << p1.age << "姓名为:" << p1.name << endl;
    13. return cout;
    14. }
    15. int main()
    16. {
    17. person p(10, "a");
    18. //直接输出 age和name
    19. cout << p<<endl;
    20. return 0;
    21. }

    重载new和delete

    重载的格式:

    1. 返回值为 void*
    2. 参数为size_t size,表示开辟空间的大小

    重载new:(成员函数)

    1. void * operator new(size_t size)
    2. {
    3. void* p = malloc(size);
    4. }

    重载delete:(成员函数)

    1. void operator delete(void *)
    2. {
    3. free(p);
    4. }

     重载()

    1. 一种为仿函数
    2. 直接重载
    1. class person
    2. {
    3. public:
    4. //仿函数:用法与函数类似
    5. void operator()()
    6. {
    7. cout << "仿函数" << endl;
    8. }
    9. int operator()(int a, int b)
    10. {
    11. return a + b;
    12. }
    13. };
    14. int main()
    15. {
    16. person p;
    17. //输出一段话
    18. p();
    19. //输出两个数的和
    20. p(10, 20);
    21. return 0;
    22. }

  • 相关阅读:
    字体压缩神器font-spider的使用
    获取公募基金持仓【数据分析系列博文】
    Android ABI
    c++模板
    Vuex应用
    java多线程
    KylinV10系统如何查找JDK路径和安装JDK
    【C语言 | 指针】指针和数组关系——剪不断,理还乱
    ElasticSearch 学习8 :ik分词器的扩展,及java调用ik分词器的analyzer
    搭建和mybatis-plus官网一样主题的网站(cos+宝塔+vercel)
  • 原文地址:https://blog.csdn.net/qq_45303986/article/details/125589219