当前位置: 首页 > news >正文

c++类和对象以及模板

类和对象

在讨论类和对象时,需要重点理解STL库中的容器以及面向对象的三大特性:封装、继承和多态。

类的特性主要体现在其整体性上。与外部函数严格要求的调用顺序不同,类域作为一个整体,其成员函数和成员变量可以在任何位置被识别,无需考虑调用顺序问题。封装通过将对象的属性和方法相结合来实现,使对象更加完善。通过访问限定符(public、private、protect)可以有选择地向外部用户提供接口。其中:

  • public:公开访问
  • private和protect:受限访问(具体区别将在继承和多态中详述)

访问权限的作用域从当前限定符开始,直到下一个限定符为止。值得注意的是:

  • class默认访问权限为private
  • struct默认访问权限为public(保持与C语言兼容)
  • 类内定义的函数默认为内联函数

封装的核心在于将数据与操作方法有机结合,隐藏对象属性和实现细节,仅对外公开交互接口。这种管理方式让类的使用更加便捷。对象大小仅包含成员变量,不包括成员函数。空对象占用1字节空间,仅用于标识对象存在。

关于this指针:

  • 不能显式传递于形参和实参
  • 可在函数内部显式使用
  • 作为形参存储在函数调用栈帧中
  • C++与C的实现本质相同,区别在于C++自动处理指针传递

类的六个默认成员函数:

构造函数(初始化)特性:

  1. 与类同名
  2. 无返回值(包括void)
  3. 对象实例化时自动调用
  4. 支持重载
  5. 未显式定义时,编译器生成默认构造函数

析构函数(清理)特性:

  1. 名称格式:~类名
  2. 无参数和返回类型
  3. 不可重载(每个类唯一)
  4. 对象生命周期结束时自动调用
  5. 未显式定义时,编译器生成默认析构函数

对于包含自定义类型的类:

  • 构造时会递归调用自定义类型的构造函数
  • 析构时先释放自身再释放自定义类型成员(避免非法访问)

拷贝构造:

  • 拷贝构造是构造函数的一个重要重载形式
  • 拷贝构造函数的参数只能有一个,而且必须是类类型对象的引用(若使用传值会直接报错,因为会引发无穷递归调用)
  • 未显示定义时,编译器生成默认拷贝构造函数(默认的会进行值拷贝(浅拷贝),自定义类型会去调用它的赋值重载)

对于构造函数的初始化,有不同的方式,我简单用代码构建一下

class test{ public: test(int & t,int & k) : val(t),key(k){} test(int t) { val = t; } private: int val; int key; };

看了这两个构造方式,想必大家也理解了,第二个就和正常函数一样,而第一个用的是成员初始化列表,而:代表初始化列表开始,初始化方式用的是(),两个初始化成员变量之间用,隔开。

还要提及构造函数的一个特点,他是支持隐式类型转换的

class test{ public: test(int t) : val(t){} private: int val; }; int main() { test t = 1; return 0; }

像这样,整形转化为自定义类型,此处的1会构造一个test的临时对象,再拷贝构造t,但是部分编译器会做优化,将其转变为用1直接构造test对象。如果想禁止这种行为,可以使用关键字explicit,会禁止隐式类型转换。

静态成员变量:

  • 在类里声明,在全局定义
  • 属于类,类的每个对象共享一个静态成员变量,且存储在静态区

静态成员函数:

  • 没有了this指针,访问时只需指定类域和访问限定符即可

这两个一般成对出现。

友元类:

  • 内部类是外部类的天生友元
  • 使用friendly对其他类进行声明,说明其他类是该类的友元类

对象:

普通对象就像上面的test t,所以我们讲特殊的,匿名对象和临时对象,这两个对象都有一个共同之处,都具有常性。

匿名对象:

  • 生命周期只在当前语句行
  • 具有常性
  • const引用的匿名对象会延长自己的生命周期,生命周期在当前局部域

内存操作符:

也说一下创建对象常用的操作符new,它和delete配对,如

class test{ public: test(int t) : val(t){} private: int val; }; int main() { test* t = new test(1); delete t; return 0; }

和malloc,free一样,他们也是一组关于内存开辟释放的操作符,有new一定要delete,否则就会造成内存泄漏。

模板与模板特化

说到模板,首先要清楚模板的关键词template,下面简单写一个模板

template<class T,class K> // <typename T> class test{ public: test(T& t,K& k) : val(t),key(k){} private: T val; K key; };

看到这段代码肯定会困惑,template后面那个是做什么用的,其实用typename会更好理解,他就是代表一个类型,至于是什么类型,看你传的参数是什么类型而自动推导的,但是实际上,模板做的工作是以你传入的类型重新构建一份代码,每次传递的不一样,都会额外生成一个,那如果有一些类型需要比正常的多出一些功能怎么办?又或者处理方式有差异怎么办?那就得提到模板的特化了,特化有两种,一个是全特化,一个是偏特化,我分别写出来,看完大家想必也会有一些自己的理解了。

全特化:

#include <iostream> // 通用模板 template <typename T> class MyTemplate { public: void print() { std::cout << "普通模板" << std::endl; } }; // 全特化版本(int 类型) template <> class MyTemplate<int> { public: void print() { std::cout << "int全特化模板" << std::endl; } }; int main() { MyTemplate<double> obj1; MyTemplate<int> obj2; obj1.print(); // 输出: 普通模板 obj2.print(); // 输出: int全特化模板 }

偏特化:

#include <iostream> // 通用模板 template <typename T> class MyTemplate { public: void print() { std::cout << "普通模板" << std::endl; } }; // 偏特化版本(指针类型) template <typename T> class MyTemplate<T*> { public: void print() { std::cout << "指针模板" << std::endl; } }; int main() { MyTemplate<double> obj1; MyTemplate<int*> obj2; obj1.print(); // 输出: 普通模板 obj2.print(); // 输出: 指针模板 }

显而易见,全特化,是指把他完全特化为具体的类型,偏特化是对部分模板参数进行特化,而不是具体的类型。如果上面有误,希望点出,你我共勉,一同进步。

http://www.cnnetsun.cn/news/1955074.html

相关文章:

  • 题解:洛谷 P10059 Choose
  • 面向软件测试从业者的脑机接口(BCI)实战入门:Neuralink API与测试关键指标深度解析
  • 革命性测试体验:jest-extended 70+个强大匹配器完全指南
  • Tangram-Android性能优化终极指南:构建流畅滚动体验的10个技巧
  • 为什么你的团队用不好Copilot?——5个被忽略的敏捷上下文适配陷阱(含Jira+GitHub Actions自动化流水线配置模板)
  • KotlinPoet社区贡献指南:如何参与开源项目并提交你的第一个PR
  • 如何快速上手Multitarget-tracker:5分钟入门多目标跟踪
  • 1000_Projects安全工具开发:从端口扫描器到密码破解器完整指南
  • 别再只用密码了!聊聊身份认证三要素:从USB Key到生物识别的实战选择
  • GitHub汉化插件终极指南:3分钟实现GitHub界面全中文化
  • 【实战指南】VSCode Python项目内模块导入:从PYTHONPATH配置到IDE环境变量全解析
  • ViGEmBus虚拟手柄驱动:Windows游戏控制的终极解决方案
  • Kandinsky-5.0-I2V-Lite-5s参数详解:随机种子复现机制与提示扩写功能实测效果
  • 基于AliceMind基础模型的春联定制方案:支持节日/行业/地域关键词扩展
  • 欧拉角、quat四元组和旋转矩阵的关系
  • 单元测试 Mock不Mock?
  • 【限时解密】2026奇点大会未公开闭门报告:AI编程助手在金融级代码审计、合规注释生成、跨语言重构三大高危场景的真实失效案例(仅剩97份内部摘要)
  • 【生成式编程安全生死线】:从GitHub Copilot到CodeWhisperer,必须启用的4层静态+动态校验机制
  • 别再手动轮询了!用DMA+ADC1多通道采集传感器数据,解放你的STM32/APM32主循环
  • 如何编写Controller的测试代码?
  • 《RocketMQ实战与进阶》 04 消息发送常见错误与解决方案
  • 苏州2026年,探秘苏州灌装机工厂的智造新篇章
  • 富集分析结果太杂乱?3个ggplot2技巧让你的气泡图秒变高颜值SCI配图
  • 构建智能能源管理系统的7个关键技术突破:OpenEMS实战指南
  • 1Panel+Docker私有仓库实战:解决镜像拉取慢/失败问题(含WordPress案例)
  • 用周立功CAN分析仪抓包解析电动汽车充电握手报文(BMS/充电机通信实战)
  • YzmCMS 5.3.0 ‘采集节点’功能竟是SSRF后门?一次对功能滥用的深度安全审计
  • BetterNCM-Installer:一键解锁网易云音乐PC版的终极插件管理器
  • Python自动化操作Creo的5个实用技巧(附代码示例)
  • GSV9001E@ACP# 参数规格 + 产品特色总结分享