16- C++多态-4 (C++)

这篇具有很好参考价值的文章主要介绍了16- C++多态-4 (C++)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

第五章 多态

5.1 多态的引入

思考:在之前实现的英雄模型中,假如实现某个接口可以传入一个英雄,在该接口中可以对英雄的力量、敏捷和智力进行加强,请问该接口的参数该如何设计?

以上解决办法利用了C++中的多态,接下来让我们来了解一下 C++中的多态

多态:一个函数有多种形态。

多态的分类:静态联编 动态联编

通常来说联编就是将模块或者函数合并在一起生成可执行代码的处理过程,同时对每个模块或者函数调用分配内存地址,并且对外部访问也分配正确的内存地址,它是计算机程序彼此关联的过程。按照联编所进行的阶段不同,可分为两种不同的联编方法:静态联编动态联编

5.2 静态联编

5.2.1 静态联编的概念

静态联编是指联编工作在编译阶段完成的,这种联编过程是在程序运行之前完成的,又称为早期联编。要实现静态联编,在编译阶段就必须确定程序中的操作调用(如函数调用)与执行该操作代码间的关系,确定这种关系称为束定,在编译时的束定称为静态束定。静态联编对函数的选择是基于指向对象的指针或者引用的类型。其优点是效率高,但灵活性差

5.2.2 静态联编的体现

1、隐藏

2、函数的的重载

3、运算符重载

4、泛型编程

5.3 运算符重载

5.3.1 运算符重载概述

1、运算符重载,就是对已有的运算符重新进行定义,赋予其另一种功能,以适应不同的数据类型。(运算符重载不能改变本来寓意,不能改变基础类型寓意)

2、运算符重载(operator overloading)只是一种 语法上的方便 ,也就是它只是另一种函数调用的方式。

3、在c++中,可以定义一个处理类的新运算符。这种定义很像一个普通的函数定义,只是函数的名字由关键字operator及其紧跟的运算符组成。差别仅此而已。它像任何其他函数一样也是一个函数,当编译器遇到适当的模式时,就会调用这个函数。

4、可以重载的运算符

16- C++多态-4 (C++),C语言,c++,开发语言,c语言

 5、不可重载的运算符:

  • 成员访问运算符(.)

  • 成员指针访问运算符(->)

  • 域运算符(::)

  • 长度运算符(sizeof)

  • 条件运算符(: ?)

  • 预处理符号(#)

5.3.2 运算符重载实例

#include <iostream>
#include <string>
#include <cstring>
#include <cstdio>

using namespace std;

class Test
{
public:
    int data;
    char *ptr;

    // 默认构造函数
    Test()
    {
        std::cout << "Test() " << std::endl;
    }

    // 带参数的构造函数
    Test(int data, const char *src)
    {
        this->data = data;
        if (src)
        {
            std::cout << "struct test(data)" << std::endl;
            this->ptr = new char[std::strlen(src) + 1];
            std::strcpy(this->ptr, src);
        }
        else
        {
            ptr = new char[10];
        }
    }

    //拷贝构造函数,调用时间:使用一个构造好的对象初始化一个新的对象
    Test(const Test &t)
    {
        cout << "Test(const Test &t)" << endl;
        //实现深拷贝
        this->data = t.data;
        //this->ptr = t.ptr; //浅拷贝
        if (strlen(t.ptr))
        {
            this->ptr = new char[strlen(t.ptr)+1];
            strcpy(this->ptr, t.ptr);
        }
        else
            ptr = new char[10];
    }

    //该运算符重载函数由 左操作数调用,右操作数当做实参传递给该函数,触发:t1 + t3 -> t1.operator + (t3)
    Test operator + (const Test &t)  //operator 操作符
    {
        cout << "Test operator + (Test &t)" << endl;
        Test val;
        val.data = this->data + t.data;
        val.ptr = new char[strlen(this->ptr) + strlen(t.ptr) + 1];
        //将分配的堆空间初始化为/0
        memset(val.ptr, 0, strlen(this->ptr) + strlen(t.ptr) + 1);

        strcat(val.ptr, this->ptr);
        strcat(val.ptr, t.ptr);
        return val;
    }

    bool operator > (const Test &t)
    {
        cout << "bool operator > (const Test &t)" << endl;
        if (strcmp(this->ptr, t.ptr) > 0)
            return true;
        return false;
    }

    char operator [](int index)
    {
        cout << "char operator [](int index)" << endl;
        if (index < 0 || index >= strlen(ptr))
            return '\0';
        return ptr[index];
    }

    Test &operator = (const Test &t)
    {
        cout << "Test &operator =(const Test &t)" << endl;
        delete[] this->ptr;
        this->ptr = new char[strlen(t.ptr) + 1];
        strcpy(this->ptr, t.ptr);

        data = t.data;
        return *this;
    }

    //前置++
    Test &operator++()
    {
        cout << "Test &operator ++(int)" << endl;
        ++data;
        return *this;
    }

    //后置++
    Test operator++(int)
    {
        cout << "Test operator ++(int)" << endl;
        Test tmp = *this;
        data++;
        return tmp;
    }

    //<<重载
    friend ostream &operator << (ostream &os, const Test &t)
    {
        os << t.data << endl;
        os << t.ptr << endl;
        return os;
    }

    // 析构函数
    ~Test()
    {
        std::cout << "~Test() delete test()" << std::endl;
        if (ptr)
            delete[] ptr;
    }
};

int main() {
#if 0
    // + 运算符重载
    Test t1(10, "hello");
    Test t2 = t1;
    cout << t2.data << endl;
    cout << t2.ptr << endl;

    Test t3(23, "world");
    cout << "********** input t3" << endl;
    Test t4 = t1 + t3;
    cout << t4.data << endl;
    cout << t4.ptr << endl;
#endif

#if 0
    // > 运算符的重载
    Test t1(10, "hello");
    Test t2(20, "hello");
    if (t1 > t2)
        cout << "t1 > t2" << endl;
    else
        cout << "t1 < t2" << endl;

    // [] 运算符的重载
    cout << "t1.ptr:" << t1.ptr << endl;
    cout << "t1[4]: " << t1[4] << endl;

    // = 符号的重载
    t1 = t2;
    cout << "-------------- t1.ptr: " << t1.ptr << endl;
    printf("t1.ptr: %p, t2.ptr: %p\n", t1.ptr, t2.ptr);  //地址
    printf("t1.ptr: %s, t2.ptr: %s\n", t1.ptr, t2.ptr);

    ++t1;
#endif
#if 0
    //前置++的重载
    Test t1(10, "hello");
    Test t2;
    t2 = ++t1;
    cout << "t2.data: " << t2.data << endl;
    cout << "t1.data: " << t1.data << endl;
    cout << "t1.ptr: " << t1.ptr << endl;

    //后置++的重载
    //Test t3;
    //t3 = t1++;
    //cout << t3.data << endl;
    //cout << t1.data << endl;

    string s("hello");
    cout << "s: " << s << endl;
    cout << "t1: " << t1 << endl;
#endif
    Test t1(10, "hello");
    cout << "++++++++++++++ t1: " << t1 << endl;
    return 0;
}

5.3.3 前置++和后置++

class A
{
private:
    int a;
public:
    A& operator++()
    {
        ++a;
        return *this;
    }
    A operator++(int)
    {
        A a = *this;
        ++*this;
        return a;
    }
};

因为后置++在实现的时候构造了一个临时对象,临时对象的构造和销毁都需要消耗一定的系统资源,所以后置++的效率比前置++的效率低

5.4 友元

5.4.1 友元函数

友元函数是可以直接访问类的私有成员的非成员函数。它是定义在类外的普通函数,它不属于任何类,但需要在类的定义中加以声明,声明时只需在友元的名称前加上关键字friend,其格式如下:

 friend 类型 函数名(形式参数);

友元函数 的使用:

1、友元函数的声明可以放在类的私有部分,也可以放在公有部分,它们是没有区别的,都说明是该类的一个友元函数。

2、一个函数可以是多个类的友元函数,只需要在各个类中分别声明。

3、友元函数的调用与一般函数的调用方式和原理一致。

4、友元函数中没有this指针

5、两个类要共享数据的时候可以使用友元函数,比如:类A中的函数需要访问类B中的成员,那

么类A中该函数要是类B的友元函数。

6、运算符重载的某些场合需要使用友元函数,例如 << 的重载

#include <iostream>

using namespace std;
class CCar;
class CDriver
{
public:
    void ModifyCar(CCar* pCar);
};
class CCar
{
private:
    int price;
    friend int MostExpensiveCar(CCar cars[], int total);
    friend void CDriver::ModifyCar(CCar *pCar);
};
void CDriver::ModifyCar(CCar *pCar) {
    pCar->price += 1000;
}

int MostExpensiveCar(CCar cars[], int total)
{
    int tmpMax = -1;
    for (int i = 0; i < total; ++i)
        if (cars[i].price > tmpMax)
            tmpMax = cars[i].price;
        return tmpMax;
}

int main() {
    return 0;
}

5.4.2 友元类

友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员)。

当希望一个类可以访问另一个类的私有成员时,可以将该类声明为另一类的友元类。定义友元类的语句格式如下:

  friend class 类名;

其中:friend和class是关键字,类名必须是程序中的一个已定义过的类。

#include <iostream>

using namespace std;

class CCar
{
private:
    int price;
    friend class CDriver;
};

class CDriver
{
public:
    CCar myCar;
    void ModifyCar()
    {
        myCar.price += 1000;
    }
};

int main() {
    return 0;
}

使用友元时注意:

  1、友元关系不能被继承

  2、友元关系是单向的,不具有交换性。若类B是类A的友元,类A不一定是类B的友元,要看在类中是否有相应的声明。

  3、友元关系具有非传递性。若类B是类A的友元,类C是B的友元,类C不一定是类A的友元,同样要看类中是否有相应的申明。

注意:友元的作用是提高了程序的运行效率(即减少了类型检查和安全性检查等都需要时间开销),但它破坏了类的封装性和隐藏性,使得非成员函数可以访问类的私有成员,不建议使用!

5.4.3 为什么输出运算符的重载需要用friend修饰呢?

如果是 重载双目操作符(即为类的成员函数),就只要设置一个参数作为右侧运算量,而左侧运算量就是对象本身。而 >> 或<< 左侧运算量是 cin或cout 而不是对象本身,所以不满足后面一点,就只能申明为友元函数了。。。

如果一定要声明为成员函数,只能成为如下的形式:

ostream & operator << (ostream &output)
{
    output << this->x << endl;
    return output;
}

5.5 动态多态

1、动态多态(动态绑定):即运行时的多态,在程序执行期间(非编译期)判断所引用对象的实际类型,根据其实际类型调用相应的方法。

2、有的工程师认为真正的多态是动态多态

3、动态多态(多态)满足的三个条件

  • 有继承关系

  • 有虚函数

  • 基类指针指向派生类对象或者基类的引用变量引用了派生类对象

5.6 重载、重写(覆盖)、隐藏

  1. 重载:overload 重载只发生在同一个作用域中,比如 一个类中的多个成员函数函数名相同,但是形参数据类型或或者个数或者顺序不相同,那么我们就称这些函数是重载。
  2. 重写:override 也叫做覆盖 重写发生在不同的作用域中(发生在基类和派生类中),而且派生类中的成员函数的名字和基类中的虚函数的名字相同,并且返回值相同,形参列表也相同!!!
  3. 隐藏隐藏发生在不同的作用域中(发生在基类和派生类中),派生类中的成员函数的名字、返回值、形参列表与基类中的普通函数完全相同, 派生类中的成员函数的名字和基类中的成员函数的名字。
  4. 相同但是形参列表不同或者返回值不同这也叫做隐藏,此时基类中的那个函数不论是普通函数还是虚函数都会被派生类中的函数隐藏。
#include <iostream>
using namespace std;

class Hero
{
public:
    virtual void huicheng()
    {cout << "Base::huicheng" << endl;}

    void func2()
    {cout << "Base::func2" << endl;}
};

class Libai : public Hero
{
public:
    void func2()
    {cout << "A::func2" << endl;}

    void func2(int x)
    {}

    void huicheng()
    {cout << "Libai::huicheng" << endl;}
    void huicheng(int x){}
};

class Caocao : public Hero
{
public:
    void func2()
    {cout << "A::func2" << endl;}

    void huicheng()
    {cout << "Caocao::huicheng" << endl;}
};

class Houyi : public Hero
{};

void goback(Hero &h)
{
    h.huicheng();
    h.func2();
}

int main() {
    Libai libai;
    Caocao caocao;
    Houyi houyi;

    goback(libai);
    goback(caocao);
    goback(houyi);

    cout << " +++++++++++++++++++ output caocao a:" << endl;
    Caocao a;
    a.func2();
    a.huicheng();

    cout << " +++++++++++++++++++ output hero *p:" << endl;
    Hero *p;
    p = &a;
    p->func2();
    p->huicheng();   //指向派生类
    return 0;
}

5.7 虚函数

5.7.1 虚函数的基本使用

C++中的虚函数的作用主要是实现了多态的机制。基类定义虚函数,子类可以重写该函数。

虚函数的定义:

virtual 函数类型 函数名(形参列表);

#include <iostream>
using namespace std;

class Base
{
public:
    virtual void func()
    {cout << "Base func: " << endl;}
    virtual void func2()
    {cout << "Base func2: " << endl;}
};

class Derived:public Base
{
public:
    void func()
    {cout << "Derived func: " << endl;}
};

int main() {
    Derived d;
    d.func();
    return 0;
}

虚函数的实现原理:虚函数的实现是由两个部分组成的,虚函数指针与虚函数表

5.7.2 虚函数指针

虚函数指针 (virtual function pointer, vptr) 从本质上来说就只是一个指向函数的指针,与普通的指针并无区别。它指向用户所定义的虚函数,具体是在子类里的实现,当子类调用虚函数的时候,实际上是通过调用该虚函数指针从而找到接口。

只有拥有虚函数的类才会拥有虚函数指针,每一个虚函数也都会对应一个虚函数指针。

5.7.3 虚函数表

存放虚函数指针的数组我们称之为 虚函数表(virtual function table, vtbl)。

每个包含了虚函数的类都包含一个虚表。当一个类(A)继承另一个类(B)时,类 A 会继承类 B 的函数。所以如果一个基类包含了虚函数,那么其派生类也可调用这些虚函数,换句话说,一个类继承了包含虚函数的基类,那么这个类也拥有自己的虚表。

我们来看以下的代码。类 A 包含虚函数vfunc1,vfunc2,由于类 A 包含虚函数,故类 A 拥有一个虚表。

class A{
public:
    virtual void vfunc1(){};
    virtual void vfunc2(){};
    void func1(){};
    void func2(){};
private:
    int m_data1, m_data2;
};

5.7.4 虚表指针(虚函数表指针)

虚表是属于类的,而不是属于某个具体的对象,一个类只需要一个虚表即可。同一个类的所有对象都使用同一个虚表。

为了指定对象的虚表,对象内部包含一个虚表的指针,来指向自己所使用的虚表。为了让每个包含虚表的类的对象都拥有一个虚表指针,编译器在类中添加了一个指针,*__vfptr,用来指向虚表。这样,当类的对象在创建时便拥有了这个指针,且这个指针的值会自动被设置为指向类的虚表。

虚表指针存在于每一个被实例化的对象中,前提是该对象中有虚函数,它总是被存放在该对象的地址首位,这种做法的目的是为了保证运行的快速性。

动态绑定, C++ 是如何利用虚表和虚表指针来实现动态绑定的。

class A{
public:
    virtual void vfunc1(){};
    virtual void vfunc2(){};
    void func1(){};
    void func2(){};
private:
    int m_data1, m_data2;
};

class B : public A
{
public:
    void vfunc1();
    void func1();
private:
    int m_data3;
};

class C: public B
{
public:
    virtual void vfunc2();
    void func2();
private:
    int m_data1, m_data4;
};

类 A 是基类,类 B 继承类 A,类 C 又继承类 B。类 A,类 B,类 C。

由于这三个类都有虚函数,故编译器为每个类都创建了一个虚表,即类 A 的虚表(A vtbl),类 B 的虚表(B vtbl),类 C 的虚表(C vtbl)。类 A,类 B,类 C 的对象都拥有一个虚表指针,*__vfptr,用来指向自己所属类的虚表。

类 A 包括两个虚函数,故 A vtbl 包含两个指针,分别指向A::vfunc1()和A::vfunc2()。

类 B 继承于类 A,故类 B 可以调用类 A 的函数,但由于类 B 重写了B::vfunc1()函数,故 B vtbl 的两个指针分别指向B::vfunc1()和A::vfunc2()。

类 C 继承于类 B,故类 C 可以调用类 B 的函数,但由于类 C 重写了C::vfunc2()函数,故 C vtbl 的两个指针分别指向B::vfunc1()(指向继承的最近的一个类的函数)和C::vfunc2()。

非虚函数的调用不用经过虚表,故不需要虚表中的指针指向这些函数。

#include <iostream>
using namespace std;

class A{
public:
    virtual void vfunc1()
    {cout << "A::virtual void vfunc1()" << endl;};
    virtual void vfunc2()
    {cout << "A::virtual void vfunc2()" << endl;};
    void func1()
    {cout << "A::void func1()" << endl;};
    void func2()
    {cout << "A::void func2()" << endl;};
};

class B : public A
{
public:
    void vfunc1()
    {{cout << "B::virtual void vfunc1()" << endl;}};
    void func1()
    {{cout << "B::void func1()" << endl;}};
};

int main() {
    B b;
    b.vfunc1();
    b.vfunc2();
    b.func1();
    b.func2();

    A *p;
    p = &b;
    p->vfunc1();
    p->vfunc2();
    p->func1();
    p->func2();
    return 0;
}

5.7.6 虚表指针、虚函数的访问

#include <iostream>
#include <Cstdio>
using namespace std;
 
typedef void(*Fun)(void);

class Base {
public:
    int x;
    virtual void f() { cout << "Base::f" << endl; }
    virtual void g() { cout << "Base::g" << endl; }
    virtual void h() { cout << "Base::h" << endl; }
};

int main() {
    Base b;
    Fun pFun = NULL;

    //虚函数表指针是对象中的第一个元素,虚函数表指针的地址就是对象的首地址
    printf("%p\n",(int*)(&b)); // &_vfptr
    //(*(int*)(&b)) : 虚函数表指针的值/虚函数表的地址
    printf("%p\n", (int*)(*(int*)(&b))); //_vfptr
    printf("%p\n", (int*)(*(int*)(&b))+2);
    printf("%p\n", (int*)(*(int*)(&b))+4);

    printf("%p\n", *(int*)(*(int*)(&b)));
    printf("%p\n", *(int*)(*(int*)(&b))+2);
    printf("%p\n", *(int*)(*(int*)(&b))+4);

    pFun = (Fun)(*((int*)(*(int*)(&b))+4));
    pFun();
}

5.8 纯虚函数和抽象基类

5.8.1 纯虚函数

1、一般来说,许多时候基类并不能确定函数的实现方法,只能确定函数的功能。但是函数调用的时候必须要用到该函数。这种情况下,C++提供了一种机制,成为纯虚函数,属于虚函数的一种,体现了面向对象的多态性。

2、定义纯虚函数是为了实现一个接口,起到一个规范的作用,规范继承这个类的程序员必须实现这个函数。

3、虚函数的语法格式如下:

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

4、纯虚函数没有函数体,只有函数声明,在虚函数声明的结尾加上=0,表明此函数为纯虚函数。

最后的=0并不表示函数返回值为0,它只起形式上的作用,告诉编译系统“这是纯虚函数”。

= 0;告诉编译器在vtable中为函数保留一个位置,但在这个特定位置不放地址

#include <iostream>

using namespace std;

//游戏中所有英雄的基类
class Hero
{
public:
    virtual void huicheng() = 0;//纯虚函数 英雄的回城功能
};

class Libai:public Hero
{
public:
    void huicheng() //重写
    {
        cout << "Libai::huicheng" << endl;
    }
};

class Caocao:public Hero
{
public:
    void huicheng()
    {
        cout << "Caocao::huicheng" << endl;
    }
};

int main()
{
    Libai h1;
    Caocao h2;

    h1.huicheng();
    h2.huicheng();

    Hero *p;
    p = &h1;
    p->huicheng();

    p = &h2;
    p->huicheng();

    return 0;
}

5.8.2 抽象基类

1、包含纯虚函数的类称为抽象类(Abstract Class)。之所以说它抽象,是因为它无法实例化,也就是无法创建对象。原因很明显,纯虚函数没有函数体,不是完整的函数,无法调用,也无法为其分配内存空间。

2、抽象类通常是作为基类,让派生类去实现纯虚函数。派生类必须实现纯虚函数才能被实例化。

#include <iostream>

using namespace std;

//游戏中所有英雄的基类
//抽象类:规定了某一类事物的特征
class Hero
{
public:
    virtual void huicheng() = 0;//纯虚函数 英雄的回城功能
    virtual void attack() = 0;
};

//假设这是对Libai类进行声明 (libai.h)
class Libai:public Hero
{
public:
    void huicheng(); //对派生类中重写基类中的纯虚函数的声明
    void attack();
};

//对Libai类的实现 (libai.cpp)
void Libai::huicheng() {
     cout << "Libai::huicheng" << endl;
}

void Libai::attack() {

}

class Caocao:public Hero
{
public:
    void huicheng()
    {
        cout << "Caocao::huicheng" << endl;
    }
};

int main()
{
#if 0
    Libai h1;
    Caocao h2;

    h1.huicheng();
    h2.huicheng();

    Hero *p;
    p = &h1;
    p->huicheng();

    p = &h2;
    p->huicheng();

  //Hero h; //抽象类不能实例化对象
#endif
    return 0;
}

抽象类实例:设计一个Shape类可以计算各种形状的面积、周长

#include <iostream>
using namespace std;
typedef unsigned int u32_t;

class Shape
{
public:
    virtual double getPermiter() = 0;
    virtual double getArea() = 0;
};

class Trangle : public Shape
{
public:
    Trangle():_a(10), _b(10), _c(10)
    {}
    Trangle(u32_t a, u32_t b, u32_t c):_a(a), _b(b), _c(c)
    {}

    double getPermiter()
    {return double(_a + _b + _c);}

    double getArea()
    {return 10000;}

private:
    u32_t _a, _b, _c;
    u32_t _permiter;
    double _area;
};

class Circle : public Shape
{
private:
    double _r;
    double _permiter;
    double _area;
    static double pi;

public:
    Circle():_r(10)
    {}
    double getPermiter();
    double getArea();
};

double Circle::pi = 3.14;
double Circle::getPermiter() {
    return 2 * pi * _r;
}

double Circle::getArea() {
    return pi * _r * _r;
}

int main() {
    Trangle x;
    cout << x.getPermiter() << endl;

    Circle x2;
    cout << x2.getPermiter() << endl;
    cout << x2.getArea() << endl;

    Shape *shape[2];
    shape[0] = &x;
    shape[1] = &x2;

    for (int i = 0; i < 2; i++)
    {
        cout << shape[i]->getArea() << endl;
        cout << shape[i]->getPermiter() << endl;
    }
    return 0;
}

5.9 虚析构函数

虚析构函数是为了解决基类的指针指向派生类对象,通过基类的指针删除派生类对象文章来源地址https://www.toymoban.com/news/detail-618607.html

#include <iostream>

using namespace std;

class Base
{
	public:
		virtual void func()
		{
			cout << "Base func"  << endl;
		}
		virtual ~Base()
		{
			cout << "~Base()" << endl;
		}
};

class Derived:public Base
{
	public:
		void func()
		{
			cout << "Derived func"  << endl;
                    cout << "访问基类的虚函数: ";
                    Base::func();
		}

		~Derived()
		{
			cout << "~Derived" << endl; 
		}
};

int main(void)
{
	Base *p = new Derived;
	delete p;
	return 0;
}

到了这里,关于16- C++多态-4 (C++)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 16-4_Qt 5.9 C++开发指南_Qt 应用程序的发布

    用 Qt 开发一个应用程序后,将应用程序提供给用户在其他计算机上使用就是应用程序的发布。应用程序发布一般会提供一个安装程序,将应用程序的可执行文件及需要的运行库安装到用户计算机上,即使用户计算机上没有安装 Qt 也能正常运行安装的程序。 Qt的应用程序发布

    2024年02月14日
    浏览(46)
  • [C++] 多态(下) -- 多态原理 -- 动静态绑定

    上一篇文章我们了解了虚函数表,虚函数表指针,本篇文章我们来了解多态的底层原理,更好的理解多态的机制。 [C++] 多态(上) – 抽象类、虚函数、虚函数表 下面这段代码中,Func函数传Person调用的Person::BuyTicket,传Student调用的是Student::BuyTicket,这就是多态调用,但是这里我

    2024年02月04日
    浏览(42)
  • 【C++进阶】继承、多态的详解(多态篇)

    作者:爱写代码的刚子 时间:2023.8.16 前言:本篇博客主要介绍C++中多态有关的知识,是C++中的一大难点,刚子将带你深入C++多态的知识。(该博客涉及到的代码是在x86的环境下,如果是在x86_64环境下指针的大小可能需要变成8bytes) 多态的概念 多态的概念:通俗来说,就是多

    2024年02月12日
    浏览(37)
  • 【C++笔记】C++多态

    多态的概念: 在编程语言和类型论中,多态(英语:polymorphism)指为不同数据类型的实体提供统一的接口。多态类型(英语:polymorphic type)可以将自身所支持的操作套用到其它类型的值上。 计算机程序运行时,相同的消息可能会送给多个不同的类别之对象,而系统可依据对

    2024年02月08日
    浏览(30)
  • [C++]:万字超详细讲解多态以及多态的实现原理(面试的必考的c++考点)

    文章目录 前言 一、多态的定义及实现 1.多态的构成条件 2.c++11的override和final 3.重载,重写,重定义的比较 4.抽象类 5.多态的原理 6.多继承中的虚函数表 7.动态绑定和静态绑定 总结 多态的概念: 多态的概念:通俗来说,就是多种形态, 具体点就是去完成某个行为,当不同的

    2023年04月22日
    浏览(57)
  • C++修炼之路之多态---多态的原理(虚函数表)

    目录 一:多态的原理  1.虚函数表  2.原理分析 3.对于虚表存在哪里的探讨 4.对于是不是所有的虚函数都要存进虚函数表的探讨 二:多继承中的虚函数表 三:常见的问答题  接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧  接上篇的多态的介绍后,接下来介绍

    2024年04月26日
    浏览(38)
  • 16-3_Qt 5.9 C++开发指南_使用QStyle 设置界面外观_实现不同系统下的界面效果的匹配

    Qt 是一个跨平台的类库,相同的界面组件在不同的操作系统上显示效果是不一样的。QStyle是封装了 GUI 界面组件外观的抽象类,Qt 定义了 QStyle 类的一些子类,应用于不同的操作系统如QWindowsStyle和QMacStyle 等。这些样式是 QtGUI 模块自带的,在不同的平台上编译运行的程序具有缺

    2024年02月13日
    浏览(45)
  • C++中的多态你真的了解吗?多态原理全面具体讲解

    目录 1. 多态的概念 2. 多态的定义及实现 2.1 多态的构成条件 2.2 虚函数 2.3 虚函数的重写 2.4 C++11 override 和 final 2.5 重载、覆盖(重写)、隐藏(重定义)的对比 3. 抽象类 3.1 概念 4. 多态的原理 4.1 虚函数表 4.2多态的原理 4.3 动态绑定与静态绑定 5. 单继承和多继承关系中的虚函数表

    2024年02月04日
    浏览(31)
  • 【C++】一文带你吃透C++多态

    🍎 博客主页:🌙@披星戴月的贾维斯 🍎 欢迎关注:👍点赞🍃收藏🔥留言 🍇系列专栏:🌙 C/C++专栏 🌙那些看似波澜不惊的日复一日,一定会在某一天让你看见坚持的意义!-- 算法导论🌙 🍉一起加油,去追寻、去成为更好的自己! @TOC 提示:以下是本篇文章正文内容,

    2024年02月08日
    浏览(45)
  • 【C++学习】多态

    🐱作者:一只大喵咪1201 🐱专栏:《C++学习》 🔥格言: 你只管努力,剩下的交给时间! 多态概念:去完成某个行为,当不同的对象去完成时会产生出不同的状态。 拿生活中买火车票的例子来说,买票的人分别是普通人,学生,军人。 普通人买的是全价票 学生买的是半价

    2023年04月09日
    浏览(23)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包