C++入门基础知识八

embedded/2024/9/24 2:28:38/

1.介绍new与delete

1.malloc和free是函数,new和delete是操作符

2.malloc申请的空间不会初始化,new可以初始化

3.malloc申请空间失败时,返回的是NULL,因此必须判空,new不需要,但是new需要捕获异常

4.申请空间后会调用构造函数完成对象的初始化,delete在释放空间前会调用析构函数完成空间中资源的释放和清理

5.malloc申请空间时,需要手动计算空间大小并传递,new只需要在其后跟空间类型就可以,如果申请是多个对象,[]中指定对象个数

2.模板介绍

void Swap(int& left, int& right)
{int temp = left;left = right;right = temp;
}
void Swap(double& left, double& right)
{double temp = left;left = right;right = temp;
}
void Swap(char& left, char& right)
{char temp = left;left = right;right = temp;
}

如果是实现交换函数的话,写这么多函数重载,但其实这些函数的区别只有函数参数的类型不一样,代码代码复用率比较低,要是有新类型出现就需要用户再去写,所以可以写一个模板。

泛型编程:编写与类型无关的通用代码,是代码复写的手段。模板是泛型编程的基础

函数模板格式:

template<typename T1,typename T2,······,typename Tn>

注意:typename是用来定义模板参数关键字,也可以使用class

函数模板是一个蓝图,它本身不是函数,是编译器使用方式产生特定类型函数的模具,所以其实模版就是将本来我们应该做的事情交给编译器

在编译器阶段,对于模板函数的使用,编译器需要根据传入的实参类型来推演生成对于类型的函数以供调用,比如:但double类型使用函数模板时,编译器通过对实参类型的推演,将T确定为double类型,然后生成一份专门处理double类型的代码。

实例1:

template<typename T>void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}int main()
{int a = 1;int b = 2;cout << a << " " << b << endl;Swap(a, b);cout << a << " " << b << endl;return 0;
}

 实例2:

template<typename T>void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}int main()
{int a = 1;int b = 2;double c = 3.3;double d = 4.4;Swap(a, c);return 0;
}

这样子会报错是因为,在编译期间,当编译器看到该实例化时,需要推演实参类型,通过实参a将T推演为int,通过实参c将T推演为double类型,当模板参数列表只有一个T,所以编译器不确定是哪一个。

处理1:通过强制转换

Swap(a,(int)c)

处理2:使用显示实例化 

Swap<int>(a,c)

显式实例化就是告诉编译器T是int,不用编译器去推演T的类型

3.模板参数的匹配原则

1.一个非模板函数可以和一个同名的函数模板同时存在,而且该函数模板还可以被实例化为这个非模板函数

 

template<typename T>void Swap(T& a, T& b)
{T tmp = a;a = b;b = tmp;
}void Swap(int a, int b)
{int tmp = a;a = b;b = tmp;
}
int main()
{int a = 1;int b = 2;double c = 3.3;double d = 4.4;Swap(a, b);return 0;
}

如果推演的与非模板一样则就会使用非模板函数

如果使用显示实例化就会用模板函数

 

对于非模板函数和同名函数模板,如果其它条件相同,在调用时会优先调用非模板函数而不会从该模板产生一个实例,如果模板可以产生一个匹配更好的函数才会调用模板

int Add(int a, int b)
{return a + b;
}
template<typename T1,typename T2>
T1 Add(T1& a, T2& b)
{return a + b;
}
int main()
{int a = 1;int b = 2;double c = 3.3;//Swap<int>(a, b);Add(1, 2);Add(a, c);return 0;
}

非模板是俩个int相加,模板则是俩个可推演的类型,当参数不同为int时就会使用模板的而不是非模板。 

模板参数兼容的类型有:

1.基本数据类型:如 int、double、char、bool 等。
2.自定义类和结构体:用户定义的类型,如 struct 或 class。
3.指针类型:如 int*、double* 等。
4.引用类型:如 int&amp;、const double&amp; 等。
5.标准库类型:如 std::vector&lt;T&gt;、std::string 等。
6.枚举类型:自定义的 enum 类型。

只要在调用模板时传入的类型与 T 兼容,编译器就能成功推导出模板参数。

类模板

类模板定义格式

template<class T1,class T2,······,class Tn>

class A

{

        //内容

}; 

 

template<class T>
class zym
{
public:zym(size_t capacity = 10):_Date(new T[capacity]),_size(0),_capacity(capacity){}~zym();
private:T* _Date;size_t _size;size_t _capacity;
};
template<class T>
zym<T>::~zym()
{//
}
int main()
{zym<int> a;return 0;
}

如果在类外定义析构还需要再写一次模板,告诉编译器这个函数是这个模板的析构函数

在 C++ 中,类的成员函数(包括析构函数)的定义需要在类外部进行时,必须明确指定模板参数。这是因为编译器需要知道该成员函数与哪个模板实例相关联。
原因

1.模板实例化:
当你在类内部声明一个模板成员函数时,编译器不会自动生成它的定义。你需要在外部明确告诉编译器该成员函数是为哪个特定类型的实例化而定义的。
2.编译器的工作方式:
编译器在处理模板时,会在需要时生成特定类型的代码。如果你在类外部定义析构函数而不指明模板参数,编译器无法知道该函数属于哪个具体的模板实例。

示例
template &lt;class T&gt;
class zym {
public:
    zym(size_t capacity = 10);
    ~zym();
private:
    T* _Date;
    size_t _size;
    size_t _capacity;
};

// 外部定义析构函数,必须指定模板参数
template &lt;class T&gt;
zym&lt;T&gt;::~zym() {
    delete[] _Date;  // 释放内存
}

总结
在外部重新写一次模板参数是为了清晰地告诉编译器这个成员函数属于哪个模板实例。这是 C++ 模板机制的一个基本要求。

4.模板实例化

类模板实例化与函数模板实例化不同,类模板实例化需要在类模板名字后面跟<>,然后将实例化的类型放在<>中,类模板名字不是真正的类,实例化的结果才是真正的类

zym<int> s1;

//zym是类名,zym<int> 才是类 

5.栈的实现 

template<typename T>
class Stack
{
public:Stack(int n = 4):_array(new T[n]),_size(0),_capacity(n){}~Stack(){delete[] _array;_array = nullptr;_size = _capacity = 0;}void Push(const T& x);private:T* _array;size_t _capacity;size_t _size;
};template<class T>
void Stack<T>::Push(const T& x)
{if (_size == _capacity){T* tmp = new T[_capacity * 2];memcpy(tmp, _array, sizeof(T) * _size);delete[] _array;_array = tmp;_capacity *= 2;}_array[_size++] = x;
}int main()
{// 类模板都是显示实例化Stack<int> st1; // intst1.Push(1);st1.Push(2);st1.Push(3);Stack<double> st2; // doublest2.Push(1.1);st2.Push(1.1);st2.Push(1.1);Stack<double>* pst = new Stack<double>;//...delete pst;return 0;
}

 

首先pst指向的是堆区上的一个地址,内容是私有成员变量,私有成员变量_array有指向堆区上的一片空间,当delete pst时,会先调用Stack的析构函数释放_array指向的空间,然后再释放私有成员变量的空间。

6.string类的简单介绍

int main()
{string s1;string s2("hello world");string s3(s2);cout << s1 << endl;cout << s2 << endl;cout << s3 << endl;//cin >> s1;//cout << s1 << endl;string s4(s2, 6, 2);cout <<"s4:"<< s4 << endl;string s5(s2, 6);cout << "s5:"<<s5 << endl;string s6("hello world", 5);cout << "s6:"<<s6 << endl;string s7(10, 'X');cout << "s7:"<<s7 << endl;//s6[10];s6[0] = 'x';cout << s6 << endl;return 0;
}

 

s1没有内容为空

s2参数为“hello world”

s3是拷贝了s2

s4是需要一个string类的实例,6是从第六个开始,2是取俩个字符停下(若超过能取的最长也只能取到最后一个停止)

s5是从第六个开始到最后一个取完

s6是取“hello world”的前五个

s7是把‘X’重复十次来实例

s6有用了operator[]把索引为0的地方重新赋值为‘x’ 


http://www.ppmy.cn/embedded/115853.html

相关文章

使用豆包Marscode 创建了一个”天气预报“小应用

以下是「豆包MarsCode 体验官」优秀文章&#xff0c;作者一拳干爆显示器。 前言 本文介绍了我第一次使用我在MarsCode IDE制作了一款天气预报的应用 其中在正文的头部以及结语部分发表了我在MarsCode编程中的体验情况&#xff0c;而正文的中间主要是我项目制作的细节步骤 豆…

C语言从头学62——学习头文件stdlib.h(一)

stdlib.h是一个非常重要的头文件&#xff0c;其中定义了使用频率很高的宏、函数等。 一、数据类型 size_t&#xff1a;运算符sizeof的返回值类型 wchar_t&#xff1a;宽字符类型 二、宏 NULL&#xff1a;空指针&#xff08;用于声明后但未使用的指针的赋初…

嘉宾云集旌城 只为大赛而来 2024ISGC国际烈酒(中国)大奖赛在德阳落下帷幕

秋高气爽、古蜀之源&#xff0c;迎来第六届国际烈酒&#xff08;中国&#xff09;大奖赛&#xff1b;五谷丰登、重装之都&#xff0c;齐聚百名国际烈酒大奖赛评委。 9月18日&#xff0c;由德阳市人民政府、国家葡萄酒及白酒露酒产品质量检验检测中心、上海合作组织多功能经贸平…

7、论文阅读:20 年来的物体检测:一个调查

目标检测综述论文:Object Detection in 20 Years: A Survey 前言引言20年来的目标检测目标检测路线图里程碑A Survey) 前言 本文从技术演变的角度广泛回顾了这个快速发展的研究领域(1990s - 2022s)。本文涵盖了许多主题,包括历史上的目标检测的里程碑、检测数据集、指标、…

字母与符号检测系统源码分享

字母与符号检测检测系统源码分享 [一条龙教学YOLOV8标注好的数据集一键训练_70全套改进创新点发刊_Web前端展示] 1.研究背景与意义 项目参考AAAI Association for the Advancement of Artificial Intelligence 项目来源AACV Association for the Advancement of Computer V…

IPsec-VPN中文解释

一 IPsec-VPN 实操 (点到点) 网络括谱图 IPSec-VPN 配置思路 1 配置IP地址 FWA:IP地址的配置 [FW1000-A]interface GigabitEthernet 1/0/0 [FW1000-A-GigabitEthernet1/0/0]ip address 10.1.1.1 24 //配置IP地址 [FW1000-A]interface GigabitEthernet 1/0/2 [FW10…

threejs加载高度图渲染点云,不支持tiff

问题点 使用的point来渲染高度图点云&#xff0c;大数据图片无效渲染点多&#xff08;可以通过八叉树过滤掉无效点增加效率&#xff0c;这个太复杂&#xff09;&#xff0c;但是胜在简单能用 效果图 code 代码可运行&#xff0c;无需npm <!DOCTYPE html> <html la…

Windows本地制作java证书(与jeecgboot配置本地证书ssl问题)

1&#xff1a;JDK生成自签证书SSL,首先以管理员身份运行CMD窗口&#xff0c;执行命令 keytool -genkey -alias testhttps -keyalg RSA -keysize 2048 -validity 36500 -keystore "F:/ssl/testhttps.keystore"F:\ssl>keytool -genkey -alias testhttps -keyalg R…