首页 > 其他分享 >类的memory以及抽象类继承学习(含测试代码)

类的memory以及抽象类继承学习(含测试代码)

时间:2023-04-21 17:26:38浏览次数:42  
标签:int a6 private memory 测试代码 对齐 抽象类 class 指针

#include <iostream>
#include <cstdio>
#include <queue>
#include <vector>
#define ll long long
using namespace std;
/*
注意:
    输出不同可能对齐参数或者编译器不同有关。
*/
//模板类输出方法
template <class T>
int size(T lim)
{
    return sizeof(lim);
}
/*
https://www.cnblogs.com/JingHuanXiao/p/6080726.html
class的内存分布:
    一个class占的内存分为三部分:
        非静态成员变量总合。
        加上编译器为了CPU计算,作出的数据对齐处理。 
        加上为了支持虚函数,产生的额外负担。
    抽象类一定有个虚指针,指向存放函数的虚表,在64位下该虚指针占8个字节,32位下占4个字节
*/
/*不同编译器可能有所不同,*/
//普通的int,大小是4
class A1
{
private:
    int a;
};
//这种排布方式会导致每次都进行对对齐,占用24字节
class A1_5
{
private:
    char c;
    double d;
    int a;
};
//数据对齐的int,对齐虚指针大小,总共为16
class A2
{
private:
    int a=5;
public:
    virtual void func(){}
};
//数据已经被填齐,大小仍为16
class A3
{
private:
    int a;
    int b;
public:
    virtual void func(){}
};
/*
注意:
string按照8字节对齐,总共32字节,并且不会变化。
以下为个人推测:
    vector内部实现为一个类包含3个指针,总字节会输出24,推测string也是个类,内部有4个指针。
    所以sizeof(string)以及一些其他的STL,会显示实现的类大小,并且不会因为数据的写入而扩大。
输出48
*/
class A4
{
private:
    string a;
    int b;
public:
    virtual void func(){}
};
/*
static保存在静态存储区(存储全局变量和静态变量,
这些变量的空间在程序编译时就已经分配好了)
大小为4
*/
class A5
{
private:
    int a;
    static int sta;
};
/*非抽象类的函数不占用类空间,大小为4*/
class A6
{
private:
    int a=114514;
    static int b;                             //不绑定this,C++规定不能在类中初始化static,默认初始化为0(部分编译不初始化报错)
    void print(){cout<<a<<" is here"<<endl;}
public:
    static int c;
    void func(){cout<<"I am here"<<endl;}                             //可以用空指针调用
    void func2(){cout<<a<<" I am here"<<endl;}                       //绑定了this指针,不能用空指针调用,但是可以判断this==null然后跳过
    //void func2(){if(this == nullptr) return ;cout<<a<<" I am here"<<endl;}
    static void fun2(){b++;cout<<b<<" is running here"<<endl;}            //static函数只能调用static变量
    static void fun3(){cout<<c<<" is running here"<<endl;}
    static int fun1(){return b;}
    static void funin(){A6 limm; limm.print();}      //可以作为一个private接口调用内部函数
};
int A6::b = 0;                             //使用域操作符指定类域的方法获得并初始化
int A6::c = 0;


/*--------------------------单继承----------------------*/
/*A2的数据没有对齐,编译期自动对齐,被B1继承后,B1的int将其对齐,虚指针大小不变,输出为16,单继承子类复用指针*/
//https://blog.csdn.net/lunaticzhg/article/details/115549909
/*显然和这篇文章不太一样,个人认为这里是由于先放指针,再放int从而导致两个int对齐了要求,而文中是32位,看不出差别*/
/*不过比较明确的是继承后父类的同名对象没有消失,而是被隐藏了*/
class B1 : public A2
{
private:
    int a;
public:
    virtual void func(){}
};
// 未对齐后变为24
class B2 : public A3
{
private:
    int b;
public:
    virtual void func(){}
};
/*
虚继承会传入一个虚基指针,对应虚基表,虚继承优先放入基类指针和子类,然后是父指针和父对象
此处B3会对齐为16,继承的A2也会,输出32
此时父类就是基类
*/
class B3 : virtual public A2
{
private:
    int b=3;
public:
    virtual void func(){}
};
class B4 : virtual public A2
{
private:
    int b=4;
public:
    virtual void func(){}
};
/*--------------------多继承-----------------------------*/
/*
继承所有父类指针,优先逐个放入父类,再放入子类
A2自动补齐是16,A3是16,再加上自己补齐的8
输出40
*/
class C1 :public A2,public A3
{
private:
    int c;
public:
    virtual void func(){}
};
/*--------------菱形继承------------------------*/
/*
优先放入直接两个基类虚指针(继承自父类)、父指针和直接父类对象,然后是子类对象,最后基类对象
虚拟继承的子类如果有新定义的虚函数,内部还是会有自己的虚函数表指针,也就是说虽然只有一个基类,但是子类却还是会有两个虚函数表指针,十分复杂。
“我的建议是,不要再一个virtual base class中声明nonstatic data members。如果这么做,你会距离复杂的深渊愈来愈近,终不可拔。”
*/
class D1 : public B3,public B4
{
private:
    int b=100;
public:
    virtual void func(){}
};

int main()
{
    /*----------------一般的类内存问题----------------*/
    A1 a1;
    cout<<size(a1)<<endl;
    A1_5 a105;
    cout<<size(a105)<<endl;
    A2 a2;
    cout<<size(a2)<<endl;
    A3 a3;
    cout<<size(a3)<<endl;
    A4 a4;
    cout<<size(a4)<<endl;
    A5 a5;
    cout<<size(a5)<<endl;
    /*---------------类中的static探究----------------------*/
    A6 *a6 = new A6;
    cout<<size(*(a6))<<endl;
    delete a6;
    a6 = nullptr;
    a6->fun2();
    a6->func();               //可以发现即使是空指针也可以执行
    //a6->func2();             //段错误
    a6->c++;                  //空指针也能调用
    a6->fun3();
    //a6->b++;                 //不能从外部调用private类型
    a6->funin();
    /*---------------单继承的类的大小探究---------------------*/
    B1 b1;
    cout<<size(b1)<<endl;
    B2 b2;
    cout<<size(b2)<<endl;
    B3 b3;
    cout<<size(b3)<<endl;
    cout<<endl<<endl;
    /*---------------多继承的类的大小探究---------------------*/
    C1 c1;
    cout<<size(c1)<<endl;
    cout<<endl<<endl;
    /*---------------菱形继承的类的大小探究---------------------*/
    D1 d1;
    cout<<size(d1)<<endl;
    return 0;
}

 

标签:int,a6,private,memory,测试代码,对齐,抽象类,class,指针
From: https://www.cnblogs.com/ztlsw/p/17341109.html

相关文章

  • 抽象类和普通类的区别
    抽象类和普通类的区别抽象类和普通类都是类的概念,在面向对象编程中用于组织和管理代码。它们的主要区别在于抽象类有一些特殊的属性和限制,这些属性和限制在普通类中是没有的。具体来说,抽象类是一种特殊的类,它不能被实例化。也就是说,你不能直接使用new关键字来创建抽象类的对象......
  • 【Azure Spring Cloud】在Azure Spring Apps上看见 App Memory Usage 和 jvm.menory.u
    问题描述在Azure的SpringCloud服务(官名为:SpringApps)中,在Metrics页面中查看AppMemoryUsage和jvm.memory.use,发现两则在下图中出现巨大差距。AppMemoryUsage还是在逐渐上升jvm.memory.use却断崖式下降  在AppMemoryUsage在逐渐上涨的情况下,是否会最终出现OO......
  • Java中抽象类详解
    在编程领域中,抽象类是一种至关重要的概念。它可以让我们更好地进行模块化设计,提高代码的复用性和可扩展性。只有全面掌握抽象类,才能在编程世界中游刃有余、与众不同。让我们一起踏上抽象类的学习之旅,创造出更加优秀的程序吧。在Java中,抽象类是一种用于按需定制的基础类,它帮助开发者......
  • istio: 修改默认cpu/memory limit
    1.概述默认istio的limist是:cpu:2000m memory:1024Mirequest也是很大,部署用例一多,很浪费资源,所以就想修改istio的默认配置2. 生成当前的manifest文件istioctlmanifestgenerate>generated-manifest.yaml这个文件很大,有1w多行,我就不贴出来了,这个是istio的部署......
  • 内存屏障--- asm volatile("" ::: "memory")
    转载:(14条消息)内存屏障---asmvolatile("":::"memory")_"asm(:::\"memory\")"_咕噜咕噜斯基的博客-CSDN博客CompilermemorybarrierThesebarrierspreventacompilerfromreorderinginstructions,theydonotpreventreorderingbyCPU.T......
  • java.lang.OutOfMemoryError- unable to create new native thread 问题排查
    问题描述最近连续两天大约凌晨3点,线上服务开始异常,出现OOM报错。且服务所在的物理机只能ping通,但是无法登录。报错信息如下:ERROR04-1203:01:43,930[DefaultQuartzScheduler_Worker-3]JobRunShell[JobRunShell]:211JobthrewanunhandledException:java.lang.OutOfMemoryErr......
  • 抽象类,接口,内部类
    抽象类abstract修饰符可以用来修饰方法也可以修饰类,如果修饰方法,那么该方法就是抽象方法;如果修饰类,那么该类就是抽象类。抽象类中可以没有抽象方法,但是有抽象方法的类一定要声明为抽象类。抽象类,不能使用new关键字来创建对象,它是用来让子类继承的。抽象类只能单继承抽......
  • Redis 报”OutOfDirectMemoryError“(堆外内存溢出)
    Redis报错“OutOfDirectMemoryError(堆外内存溢出)”问题如下:一、报错信息:使用Redis的业务接口,产生OutOfDirectMemoryError(堆外内存溢出),如图:格式化后的报错信息:{ "timestamp":"2023-04-1722:46:36", "status":500, "error":"InternalServerError&q......
  • java抽象类和抽象方法
    抽象类语法:   [public]?abstractclass类名[extends父类名]?[implements接口名1,接口名2,...]?  {     [private | protected | public]? [static]?[final]?类型名变量名[ =表达式1 [,变量名[ =表达式2... ]?]?]? ;   [private |......
  • c# 接口、抽象类
    接口概述接口像类一样声明,里面的成员可以包含方法的签名(是隐式public的且抽象的)、属性、事件和委托,但在接口中不可以定义数据成员(字段)和静态成员。与类不同的是,接口中仅仅是他们的声明,并不提供实现。因此接口是函数声明的集合。如果类或结构从一个接口派生,则这个类或结构负责实......