• 对象、多态和空类的大小


    什么是对象

      类就是拥有相等功能和相同的属性的对象的集合 -- 抽象的

      对象就是类的实例 -- 具体

      举个例子:

      

    class A
    {
        /*
        这里定义一些成员数据和一些操作,但是并没有指定使用这些数据和操作的“人”(实例或对象),所以说类是抽象的
        */
    }
    
    //这里指明了类A的使用对象是obj,是具体的
    A obj;

    面向对象的三大特征: 

    封装:找到变化并且把它封装起来,你就可以在不影响其它部分的情况下修改或扩展被封装的变化部分,这是所有设计模式的基础,就是封装变化,

    因此封装的作用,就解决了程序的可扩展性。 

    继承:子类继承父类,可以继承父类的方法及属性,实现了多态以及代码的重用,因此也解决了系统的重用性和扩展性,但是继承破坏了封装,

    因为他是对子类开放的,修改父类会导致所有子类的改变,因此继承一定程度上又破坏了系统的可扩展性,所以继承需要慎用,

    只有明确的IS-A关系才能使用,同时继承在在程序开发过程中重构得到的,而不是程序设计之初就使用继承,很多面向对象开发者滥用继承,

    结果造成后期的代码解决不了需求的变化了。因此优先使用组合,而不是继承,是面向对象开发中一个重要的经验。 

    多态:接口的多种不同的实现方式即为多态。接口是对行为的抽象,刚才在封装提到,找到变化部分并封装起来,但是封装起来后,怎么适应接下来的变化?

    这正是接口的作用,接口的主要目的是为不相关的类提供通用的处理服务,我们可以想象一下。比如鸟会飞,但是超人也会飞,通过飞这个接口,

    我们可以让鸟和超人,都实现这个接口,这就实现了系统的可维护性,可扩展性。 

     C++多态的实现

    1、多态分为静态多态(函数重载和泛型编程)和动态多态(虚函数);

    2、静态多态和动态多态的实际区别就是函数地址是早绑定还是晚绑定。如果函数调用时在编译期间就可以确定函数的调用地址并产生代码,就是静态的,也就是说地址是早绑定的(函数重载和泛型编程)。

    而如果函数调用地址不能在编译期间确定,需要在运行时才能确定,这就属于晚绑定(通过虚函数实现);

    3、C++的多态性用一句话概括就是:在基类的函数前加上virtual关键字,在派生类中重写该函数,运行时基类指针或引用将会根据对象的实际类型来调用相应的函数。

    如果对象类型是派生类,就调用派生类的函数;如果对象类型是基类,就调用基类的函数

    类的大小

    1、C++标准规定类的大小不为0,空类的大小为1,当类不包含虚函数和非静态数据成员时,其对象大小也为1。

    当类里面含有空的构造函数和虚析构函数的时候,类的到小也为1-->虚析构函数的内存大小也为1

    #include<iostream>
    using namespace std;
    class ClassA
    {};
    class ClassB
    {
        ClassB()
        {
    
        }
    };
    class ClassC
    {
        ~ClassC()
        {
    
        }
    };
    class ClassD
    {
        ClassD()
        {
    
        }
        ~ClassD()
        {
    
        }
    };
    int main()
    {
        //类大小
        cout << sizeof(ClassA) << endl;//1
        cout << sizeof(ClassB) << endl;//1
        cout << sizeof(ClassC) << endl;//1
        cout << sizeof(ClassD) << endl;//1
        system("pause");
    }
    View Code

    2、如果在类中声明了虚函数(不管是1个还是多个),那么在实例化对象时,编译器会自动在对象里安插一个指针指向虚函数表VTable,在32位机器上,一个对象会增加4个字节来存储此指针,它是实现面向对象中多态的关键。而虚函数本身和其他成员函数一样,是不占用对象的空间的。 

    #include<iostream>
    using namespace std;
    class ClassA
    {
        virtual void GetNum();
    };
    class ClassB
    {
        virtual void GetNum1();
        virtual void GetNum2();
    };
    int main()
    {
        //类大小
        cout << sizeof(ClassA) << endl;//  4或8,也就是一个指针的大小
        cout << sizeof(ClassB) << endl;//  4或8,不管有几个虚函数,都和一个虚函数大小一样
        system("pause");
    }
    View Code

    3、如果类里面包含静态成员数据,那么静态成员数据不占类内内存

    #include<iostream>
    using namespace std;
    class ClassA
    {
    private:
        int a;
    };
    class ClassB
    {
    private:
        int a;
        static int b;
    };
    int main()
    {
        static int b=0;
        //类大小
        cout << sizeof(ClassA) << endl;//  4
        cout << sizeof(ClassB) << endl;//  4
        system("pause");
    }

    我们来看下面一个例子:

  • 相关阅读:
    解决laravel 429请求错误
    laravel的Validation检索验证错误消息
    Laravel通过用户名和密码查询
    Javascript 利用 switch 语句进行范围判断
    解决SourceTree每次拉取提交都需要输入密码的问题
    nginx ip配置反向代理为本地域名
    Linux top命令详解
    《Inside C#》笔记(六) 属性、数组、索引器
    《Inside C#》笔记(五) 方法
    《Inside C#》笔记(四) 类
  • 原文地址:https://www.cnblogs.com/-citywall123/p/12746196.html
Copyright © 2020-2023  润新知