c++柔性数组、友元、类模版

目录

1、柔性数组: 

 2、友元函数:

3、静态成员 

注意事项

面试题:c/c++ static的作用?

C语言:

C++:

为什么可以创建出 objx

4、对象与对象之间的关系

5、类模版


1、柔性数组: 

#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<iostream>using namespace std;class MyString
{
private:struct  StrNode{int refcount; //引用计数int slen;int capa;char data[0]; //数组不填或填0就成为柔性数组};private:StrNode* pstr;static const size_t DAFAUSIZE = 32;static const size_t INCSIZE = 2;static StrNode* GetMem(rsize_t n){size_t total = (n > DAFAUSIZE) ? n + 1 : DAFAUSIZE;StrNode* s = (StrNode*)malloc(sizeof(StrNode) + sizeof(char) * total);memset(s, 0, sizeof(StrNode) + sizeof(char) * total);s->capa = total - 1;return s;}static void  FreeMem(StrNode *p){free(p);}
public:MyString(const char* p = nullptr) :pstr(nullptr){if (p != nullptr){int len = strlen(p);pstr = GetMem(len);pstr->refcount = 1;pstr->slen = len;strcpy(pstr->data, p);}}MyString(const MyString &st) :pstr(st.pstr)  //st给当前对象{if (pstr != nullptr){pstr->refcount += 1; //+1 说明有两个对象持有这块空间}}MyString(MyString &&st) :pstr(st.pstr)  //移动构造{st.pstr = nullptr;}~MyString() {if (pstr != nullptr && --pstr->refcount == 0){FreeMem(pstr);}pstr = nullptr;}ostream& operator<<(ostream& out)const{if (pstr != nullptr){out << pstr->data;}return out;}
};
ostream &operator<<(ostream &out, const MyString &st)
{return st << out;
}int main()
{MyString s1 = "chengxi";MyString s2(s1);MyString s3(s2);MyString s4(s3);cout << s3 << endl;return 0;
}

 2、友元函数:

(1)不具有传递特性、继承特性、是单向的。

(2)友元函数分为:函数友元、成员函数友元、类友元

(3)友元函数是访问类的对象非公有属性。

成员函数友元:

using namespace std;
class Base;
class Test
{
private:int sum;
public:Test(int x = 0) :sum(x) {}void SetSum(int x = 0){sum = x;}int GetSum()const { return sum; }int Add(const Base &it);
};class Base
{friend int Test::Add(const Base& it);//成员函数友元int num;
public:Base(int x = 0) :num(x){}
};
int Test::Add(const Base& it)
{return this->sum + it.num;
}int main()
{Test t1(100);Base b1(2);t1.Add(b1);
}

类友元: 

using namespace std;
//Test对象访问base的私有和公有,注意方向
class Base
{friend class Test; 
private:int num;
public:Base(int x = 0) :num(x){}
};class Test
{
private:int sum;
public:Test(int x = 0) :sum(x) {}void SetSum(int x = 0){	sum = x;}int GetSum()const { return sum; }int Add(const Base &it) {return it.num + 10;}int func(const Base& it){return it.num;}
};int main()
{Test t1;Base b1;t1.Add(b1);t1.func(b1);return 0;
}

3、静态成员 

(1) 类静态成员只能在类外进行初始化,

(2)静态成员变量在数据区存储。静态量不属于对象,是被所有对象共享,不管有多少个对象,静态成员只有一份存在于数据区。

(3)静态数据可以在普通方法中使用

(4)为什么不能在参数列表中对静态成员初始化?

答:参数列表,在定义对象的时候要调用构造函数,拿参数列表对数据成员进行创建,静态成员被所有对象共享,在定义不同的对象时都要对静态成员进行构建,c++中,数据成员(对象、变量)在生存期内只能被构建一次。放在参数列表中,被构建了n次,不允许。要在类外进行初始化。

静态成员在类模版中,数据类型不同 ,就会产生不同的 “静态成员”

using namespace std;template<class T>
class Object
{
private:int value;
protected:static int num;
public:Object(int x=0):value(x){}~Object(){}
};class Test :public Object<Test>
{
public:Test(){cout << "Create Test::" << (num += 1) << endl;}
};class Base :public Object<Base>
{
public:Base() {cout << "Create Base:" << (num += 1) << endl;}
};
template<class T>
int Object<T>::num = 0;
int main() {Test t1[1];Base b1[2];return 0;
}

  • Test t1[1];:创建一个包含 1 个 Test 对象的数组,在创建 Test 对象时,会调用 Test 类的构造函数,输出相应的信息。
  • Base b1[2];:创建一个包含 2 个 Base 对象的数组,在创建 Base 对象时,会调用 Base 类的构造函数,输出相应的信息。

注意事项

由于 Object 类的静态成员变量 num 是模板化的,Object<Test> 和 Object<Base> 是不同的模板实例化,它们各自拥有独立的 num 副本。所以在创建 Test 和 Base 对象时,它们的 num 计数是相互独立的。

面试题

C语言:

(1)静态关键字修饰全局/局部变量,存在于数据区,当函数消亡时,静态变量还存在,可以&。

全局变量有static和无的区别?

(2)全局静态变量只在本文件中可见,同一工程的其他文件不可见, (私有),未用static修饰的全局变量,可以用extern在其他文件用。

(3)static修饰函数,此函数只在当前文件夹有效,在其他文件中不能用,(私有)。修饰函数本身而不是修饰返回值 static int* add() {} ,。

C++:
(1)static可以修饰类的成员,要在类外进行初始化。所有的对象都共享同一个静态成员变量,派生的类也共享(但前提是将其设置成protected /public)。

(2)静态成员变量不属于对象,无this,在常方法中可以修改静态成员变量的值,this不修饰它。

static可以修饰属性的类型,要在类外进行初始化,如果是静态常性变量可以在类内进行初始化,但必须要求是整型类型。

(3)static修饰成员方法,static void func(){}  无this指针。静态成员方法无this。

(3)static修饰的成员方法可以访问静态属性也可以访问非静态属性(非静态属性必须把对象传进来)。

静态成员方法可以通过 对象访问,也可以通过类名。

静态成员变量
  • 类的所有对象共享:静态成员变量属于类本身,而不是类的某个对象。无论创建多少个类的对象,静态成员变量都只有一份副本,被所有对象共享。
  • 需要在类外初始化:静态成员变量必须在类外进行初始化,因为它不依赖于对象的创建。

     :obja可以创建出来,指针:4字节

    #include<stdio.h>
    #include<iostream>
    using namespace std;
    class Object
    {
    private:int value;
    private:static Object objx;
    private:Object(int x = 0) :value(x) {cout << "create Obj" << this << endl;}~Object(){cout << "destroy obj:" << this << endl;}
    };
    Object Object::objx(1);int main()
    {return 0;
    }

    • 成员变量
      • int value;:一个私有成员变量,用于存储对象的值。
      • static Object objx;:一个私有静态成员变量,类型为 Object 类本身。静态成员变量属于类,而不是类的某个对象,所有该类的对象共享同一个静态成员变量。
    • 静态成员变量初始化
      • Object Object::objx(1);
        

        这行代码对 Object 类的静态成员变量 objx 进行初始化,调用了 Object 类的构造函数,并将参数 1 传递给构造函数,将 value 成员变量初始化为 1

        为什么可以创建出 objx

        虽然 Object 类的构造函数和析构函数都是私有的,通常情况下,外部代码无法直接创建 Object 类的对象。但是,静态成员变量 objx 是类的一部分,类的内部可以访问其私有成员。因此,在类的外部对静态成员变量 objx 进行初始化时,实际上是在类的作用域内调用了构造函数,这是被允许的。

         

        当程序开始执行时,在进入 main 函数之前,会先对静态成员变量进行初始化,所以 Object::objx 会被创建,调用构造函数输出创建信息。当程序结束时,静态对象 objx 会被销毁,调用析构函数输出销毁信息。

    using namespace std;
    class Object
    {
    private:int value;
    private:static Object objx;
    private:Object(int x = 0) :value(x) {cout << "create Obj" << this << endl;}~Object(){cout << "destroy obj:" << this << endl;}
    public:void Print()const { cout << "value" << value << endl; }void SetValue(int x) { value = x; }int GetValue()const { return value; }//通过静态方法将静态对象的地址返回static Object* getObject(){return &objx;}
    };
    Object Object::objx(1);int main()
    {Object* pa = Object::getObject();Object* pb = Object::getObject();if (pa == pb) { cout << "pa,pb pinter:object" << endl; }pa->Print();pa->SetValue(100);pa->GetValue();pa->Print();return 0;
    }
    • if (pa == pb) { cout << "pa,pb pinter:object" << endl; }:比较 pa 和 pb 的值,如果相等,说明它们指向同一个对象,输出相应信息。由于 objx 是静态对象,无论调用多少次 getObject() 函数,返回的都是同一个对象的地址,所以 pa 和 pb 相等。
    • 通过静态成员函数可以在类外部访问私有静态成员对象,并且由于静态成员对象只有一个实例,无论通过多少个指针访问,操作的都是同一个对象。

    4、对象与对象之间的关系

    依赖关系:用-------> 表示

    一个对象在运行期间会用到另一个对象的关系,通常在运行期间产生,并且伴随运行时的变化依赖关系也发生变化。主要表现为 :“使用关系”。

    关联关系:用——> 表示:

    静态关系,如:学生和学校,是关联关系

    在设计中。关联关系主要体现在目标类型的指针或引用。

    聚合、继承、组合等。

    5、类模版

    template<类型模版参数表>

    类模板不是类,因此无法直接实例化对象,需要在声明类时给定确定的数据类型,编译器才会以此分配内存。对于普通类而言,类的声明和类成员函数的定义可以写在不同的文件中,但是对于类模板来说,最好定义在同一个文件中。

    //define _N 10
    template<class T,int N>
    class SeqStack
    {T* data;int capa;int top;static const int stackinitsize = 100;static const int incsize = 2;static T* GetMen(size_t sz){T* newdata = (T*)malloc(sizeof(T) * sz);if (nullptr == newdata){cout << "malloc fail" << endl;exit(1);}memset(newdata, 0, sizeof(T) * sz);return newdata;}static void FreeMem(T* p){free(p);}public:SeqStack(int sz = stackinitsize) :data(nullptr), capa(sz), top(-1){//data = (T*)malloc(sizeof(T) * capa); //只申请空间不构建对象data = GetMen(capa);}~SeqStack(){}int size()const { return top + 1; }bool empty()const { return size() == 0; }int capacity()const { return capa; }bool full()const { return size() == capacity(); }bool push(const T& x){if (full())return false; //满了调增容函数 top += 1;new(&data[top]) T(x);   //data[++top] = x;构建对象return true;}bool gettop(T *val) {if (empty())return false;val = data[top];return true;}bool poptop(T& val){if (empty())return false;val = data[top];(&data[top])->~T(); //析构top中的对象top -= 1;return true;}bool pop(){if (empty())return false;(&data[top])->T();top -= -1;return true;}};
    int main()
    {SeqStack<int, 10> istack;   //using T:int N:10}
    int main() {ClassName<int> intObj(10);  // 实例化类模板,创建一个处理 int 类型的类对象int result = intObj.getData();std::cout << "Result: " << result << std::endl;ClassName<double> doubleObj(3.14);  // 实例化类模板,创建一个处理 double 类型的类对象double dResult = doubleObj.getData();std::cout << "Result: " << dResult << std::endl;return 0;
    }

    本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/bicheng/75671.shtml

    如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

    相关文章

    主相机绑定小地图

    资源初始化&#xff1a;在类中通过 property 装饰器定义主相机、小地图相机、小地图精灵等资源属性&#xff0c;便于在编辑器中赋值。在 start 方法里&#xff0c;当确认这些资源存在后&#xff0c;创建渲染纹理并设置其大小&#xff0c;将渲染纹理与小地图相机关联&#xff0c…

    linux-core分析-柔性数组越界访问

    文章目录 core的调用栈core分析修改修改原因柔性数组定义代码修改总结core的调用栈 vocb core 崩溃:core的大小都是573M左右 Program terminated with signal SIGSEGV, Segmentation fault. #0 0x0000007f789af0d0 in strlen () from /lib/libc.so.6[Current thread is 1 (LW…

    leetcode 代码随想录 数组-区间和

    题目 给定一个整数数组 Array&#xff0c;请计算该数组在每个指定区间内元素的总和。 输入&#xff1a; 第一行输入&#xff1a;为整数数组 Array 的长度 n&#xff0c;接下来 n 行&#xff0c;每行一个整数&#xff0c;表示数组的元素。随后的输入为需要计算总和的区间&…

    部署nerdctl工具

    nerdctl 是一个专为Containerd设计的容器管理命令行工具&#xff0c;旨在提供类似 Docker 的用户体验&#xff0c;同时支持 Containerd 的高级特性&#xff08;如命名空间、compose等&#xff09;。 1、下载安装 wget https://github.com/containerd/nerdctl/releases/downlo…

    【论文笔记】DeepSeek-R1 技术报告

    最强开源LLM&#xff0c;性能和效果都很棒&#xff1b;在数学、代码这种有标准正确答案的场景&#xff0c;表现尤为突出&#xff1b;一些其他场景的效果&#xff0c;可能不如DeepSeek-V3和Qwen。 Deepseek-R1没有使用传统的有监督微调sft方法来优化模型&#xff0c;而使用了大规…

    YOLO学习笔记 | 基于YOLOv5的车辆行人重识别算法研究(附matlab代码)

    基于YOLOv5的车辆行人重识别算法研究 🥥🥥🥥🥥🥥🥥🥥🥥🥥🥥🥥🥥🥥🥥 摘要 本文提出了一种基于YOLOv5的车辆行人重识别(ReID)算法,结合目标检测与特征匹配技术,实现高效的多目标跟踪与识别。通过引入注意力机制、优化损失函数和轻量化网络结构…

    Buildroot与Yocto介绍比对

    Buildroot 和 Yocto 是嵌入式 Linux 领域最常用的两大系统构建工具&#xff0c;它们在功能定位、使用方法和适用场景上有显著差异。以下从专业角度对两者进行对比分析&#xff1a; 一、Buildroot 核心功能与特点 1. 功能定位 轻量级系统构建工具&#xff1a;专注于快速生成精…

    VUE3初始化项目安装

    本次就是作为实验使用&#xff0c;包括安装过程中遇到的问题&#xff0c;供大家提供参考&#xff0c;话不多说&#xff0c;看过程&#xff1a; 第1步&#xff1a;首先分别安装node.js和npm&#xff0c;这步网上有很多资料&#xff0c;很简单&#xff0c;过程省略了&#xff0c…

    GO语言学习(17)Gorm的数据库操作

    目录 &#x1f3c6;前言 1.Gorm的简介 2.GORM连接数据库 2.1 配置DSN Mysql&#xff0c;TiDB&#xff0c;MariaDB PostgreSQL SQL Server SQLite 2.2 gorm.Open连接数据库 3.数据库连接池的配置 4.使用GORM对数据库进行操作&#xff08;重点&#xff09; 4.1 创…

    【JavaEE】网络原理详解

    1.❤️❤️前言~&#x1f973;&#x1f389;&#x1f389;&#x1f389; Hello, Hello~ 亲爱的朋友们&#x1f44b;&#x1f44b;&#xff0c;这里是E绵绵呀✍️✍️。 如果你喜欢这篇文章&#xff0c;请别吝啬你的点赞❤️❤️和收藏&#x1f4d6;&#x1f4d6;。如果你对我的…

    第十五届蓝桥杯单片机省赛程序设计试题

    同时也是积分赛——测量NE555输出脉冲频率 第十五届 蓝桥杯 单片机设计与开发项目 省赛1 第二部分 程序设计试题&#xff08;85 分&#xff09; &#xff08;大学组&#xff09; 一 基本要求 1、使用大赛组委会统一提供的四梯单片机竞赛实训平台&#xff0c;完成本试题程序…

    JavaScript智能对话机器人——企业知识库自动化

    引言 内部知识管理常面临信息分散、查找困难的问题。本文将使用Node.js和虎跃办公的智能对话API&#xff0c;构建企业级知识问答机器人&#xff0c;支持自然语言查询和自动学习。 核心技术 自然语言处理&#xff08;NLP&#xff09;意图识别机器学习模型微调REST API集成 代…

    元宇宙浪潮下,前端开发如何“乘风破浪”?

    一、元宇宙对前端开发的新要求 元宇宙的兴起&#xff0c;为前端开发领域带来了全新的挑战与机遇。元宇宙作为一个高度集成、多维互动的虚拟世界&#xff0c;要求前端开发不仅具备传统网页开发的能力&#xff0c;还需要掌握虚拟现实&#xff08;VR&#xff09;、增强现实&#…

    Spring Boot 3.4.3 基于 Caffeine 实现本地缓存

    在现代企业级应用中,缓存是提升系统性能和响应速度的关键技术。通过减少数据库查询或复杂计算的频率,缓存可以显著优化用户体验。Spring Boot 3.4.3 提供了强大的缓存抽象支持,而 Caffeine 作为一款高性能的本地缓存库,因其优异的吞吐量和灵活的配置,成为许多开发者的首选…

    QT Quick(C++)跨平台应用程序项目实战教程 6 — 弹出框

    目录 1. Popup组件介绍 2. 使用 上一章内容完成了音乐播放器程序的基本界面框架设计。本小节完成一个简单的功能。单击该播放器顶部菜单栏的“关于”按钮&#xff0c;弹出该程序的相关版本信息。我们将使用Qt Quick的Popup组件来实现。 1. Popup组件介绍 Qt 中的 Popup 组件…

    DuckDB系列教程:如何分析Parquet文件

    Parquet 是一种强大的、基于列的存储格式&#xff0c;适用于实现更快捷和更高效的数据分析。您可以使用 DuckDB 这种内存型分析数据库来处理 Parquet 文件并运行查询以对其进行分析。 在这篇文章中&#xff0c;我们将逐步介绍如何使用 DuckDB 对存储在 Parquet 文件中的餐厅订单…

    异步框架使用loguru和contextvars实现日志按Id输出

    需求阐述 工作中使用fastStream模块消费kafka事件的时候&#xff0c;遇到以下问题。1. 由于main.py模块要用到许多其他模块 &#xff0c;main模块&#xff0c;和其他模块都有日志输出。2. 要实现异步消费事件&#xff0c;但是又不希望日志打印的很乱。3. 想着在每次消费事件的…

    【HTTPS协议】

    文章目录 一、HTTPS二、HTTPS协议五种加密方案1.只使用对称加密2.只使用非对称加密3.双方都使用非对称加密4.对称加密非对称加密中间人攻击理解数字签名CA机构和证书 5. 对称加密非对称加密证书认证中间人篡改证书&#xff1f;中间人调包整个证书&#xff1f; 常见问题总结 一、…

    算法设计学习8

    实验目的及要求&#xff1a; 通过深入学习树&#xff08;Tree&#xff09;和二叉树&#xff08;Binary Tree&#xff09;这两种重要的数据结构&#xff0c;掌握它们的基本概念、性质和操作&#xff0c;提高对树形结构的理解和应用能力。通过本实验&#xff0c;学生将深化对树和…

    P17_ResNeXt-50

    &#x1f368; 本文为&#x1f517;365天深度学习训练营 中的学习记录博客&#x1f356; 原作者&#xff1a;K同学啊 一、模型结构 ResNeXt-50由多个残差块&#xff08;Residual Block&#xff09;组成&#xff0c;每个残差块包含三个卷积层。以下是模型的主要结构&#xff1…