建立一个通用的类,其类中的类型不确定,用一个虚拟类型替代
template
类
template ----->表示开始创建模板
typename -->表明后面的符号是数据类型,typename 也可以用class代替
T ----->表示数据类型,可以其他符号代替
使用类模板的时候,需要表明模板参数类型
#include
using namespace std;
//声明创建类模板
template
class A
{
private:
T n;
N b;
public:
A(){}
A(T n, N b):n(n),b(b){}
void show()
{
cout << n << endl;
cout << b << endl;
}
};
int main()
{
A a("zhangsan",1001);//使用类模板的时候,需要表明模板参数类型
a.show();
A b(34,'w');
b.show();
return 0;
}
更优雅的解决代码中的问题和异常,可以发现异常并处理进行分开
#include
using namespace std;
int fun(int a, int b)
{
if(b!=0)
{
return a/b;
}
else
{
throw -1;
}
}
int main()
{
try{
fun(9,0); //把可能出现异常的代码用try包裹起来
cout << "hello world" << endl;
}catch(int e)
{
if(e == -1)
{
cout << "分母不能为0" << endl;
}
}
return 0;
}
用来修饰变量,作为自动类型推导,推导出变量的数据类型
1> 使用auto修饰变量时,必须初始化
2> auto的右值,可以是右值,也可以是表达式,还可以是函数的返回值
3> auto不能直接声明数组
4> auto不能作为函数的形参
5> auto不能修饰非静态成员
主要用于修饰冗长的数据类型,使用在函数模板中,依赖模板参数的变量。
当你需要一个匿名的、临时的、需要获得外界变量的函数时,可以用lambda来完成。
#include
int main() {
int a = 1, b = 2;
// 值捕获
auto sum1 = [a, b]() { return a + b; };
std::cout << "sum1: " << sum1() << std::endl;
// 引用捕获,由于是引用,出了作用域也会修改a、b值
auto sum2 = [&a, &b]() { return a + b; };
std::cout << "sum2: " << sum2() << std::endl;
// 混合捕获
auto sum3 = [a, &b]() { return a + b; };
std::cout << "sum3: " << sum3() << std::endl;
// 值捕获,但使用mutable使其可修改 出了作用域后不修改值
auto sum4 = [a, b]() mutable { a = a + 1; return a + b; };
std::cout << "sum4: " << sum4() << std::endl;
// 指定返回类型
auto sum5 = [a, b]() -> int { return a + b; };
std::cout << "sum5: " << sum5() << std::endl;
return 0;
}
这是C++编译器自动执行的类型转换,通常在表达式中出现时发生。例如,将较小的整数转换为较大的整数类型,将整数提升为浮点数等。
通过使用强制类型转换操作符来显示执行类型转换。这种转换可能会导致数据的截断或者精度丢失,因此要小心使用。
用于基本数据类型之间的转换
以及父类指针/引用转换为子类指针/引用
还可以用于不同类型的指针之间的转换
double num_double = 3.14;
int num_int = static_cast(num_double); // 显式将double转换为int
通常用于多态类之间的指针或引用类型转换,确保类型安全。在运行时进行类型检查,只能用于具有虚函数的类之间的转换
class Base {
virtual void foo() {}
};
class Derived : public Base {};
Base* base_ptr = new Derived;
Derived* derived_ptr = dynamic_cast(base_ptr); // 显式将基类指针转换为派生类指针
用于添加或移除指针或引用的常量性。它可以用来去除const限定符,但要注意潜在的未定义行为
const int a =10; //
int *p;
p = &a; // 合不合法? no
//如果能这样使用,那就可以通过指针取值去改const修饰的值了,这就和const修饰相悖了
**************************************
const int num_const = 5;
int* num_ptr = const_cast(&num_const); // 去除const限定符
执行低级别的位模式转换,通常用于指针之间的类型转换。它可能导致未定义行为,因此要谨慎使用
int num = 42;
float* float_ptr = reinterpret_cast(&num); // 重新解释转换
可以使用C样式转换
int num_int = 10;
double num_double = (double)num_int; // C样式强制类型转换
函数样式转换:C++中使用的类型转换
int num_int = 10;
double num_double = double(num_int); // C++函数样式类型转换
在使用强转的时候要注意潜在问题和错误,保证操作是安全的。
63个关键字,红色(不包括class,class是修改之前的错误)的32个是c中的关键字
1>
asm
1:这是一个用于嵌入汇编语言代码的关键字。它允许你在C++代码中直接插入汇编指令,通常用于执行特定的底层操作。然而,由于现代C++提供了更强大的抽象和跨平台性,通常不建议使用这个关键字。
explicit
2:这个关键字通常用于禁止隐式类型转换的发生。当一个构造函数被声明为explicit时,它将不会在隐式类型转换中被调用,只能在显式构造函数调用中使用。
export
3:在C++中,export关键字用于指示一个模板的定义将在另一个文件中实例化。然而,在实际的C++标准中,export关键字的语法并未最终确认,并且在许多编译器中也未被实现。在C++20中,export被重新引入,但是它的主要用途是与模块化编程相关,而不是之前模板实例化的用法。
goto
4:goto是一个跳转语句,允许你无条件地将程序的控制转移到指定的标签处。然而,由于使用goto会导致代码结构变得混乱和难以维护,现代编程实践通常建议避免使用它。
register
5:在早期的C语言标准中,register关键字用于建议编译器将变量存储在寄存器中,以便提高访问速度。然而,现代编译器已经能够智能地管理寄存器分配,所以使用register关键字通常不再有明显的性能提升,并且在C++17中已被弃用。
volatile
6:volatile关键字用于告诉编译器不要对标记为volatile的变量进行优化,因为这些变量的值可能会在未知的时间被外部因素改变,比如硬件中断或多线程环境中的共享变量。这可以防止编译器对这些变量的读取和写入操作进行优化,以确保程序的行为是可预测的。
2> 数据类型相关的关键字
bool、true、false:对于bool类型数据的相关处理,值为true和false
char、wchar_t:char是单字符数据,wchar_t多字符数据
int、short、float、double、long:整数和实数的数据类型
signed、unsigned:定义有符号和无符号数据的说明符
auto:在c语言中,是存储类型,但是在C++中,是类型自动推导,注意事项有两个:
i> 连续定义多个变量时,初始值必须是相同数据类型,否则报错
ii> auto p=&m; 与auto* p = &m;规定是一样
explicit:防止数据隐式转换
typedef:类型重定义
sizeof:求数据类型的字节运算
3> 语句相关的关键字
switch、case、default:实现多分支选择结构
do、while、for:循环相关的关键字
break、continue、goto:跳转语句
if、else:选择结构
inline:内联函数
return:函数返回值
4> 存储类型相关的关键字
static、const、volatile、register、extern、auto
5> 构造数据类型相关
struct、union:结构体和共用体
enum:枚举
class:类
6> 访问权限:public、protected、private
7> 异常处理:throw、try、catch
8> 类中相关使用关键字
this:指代自己的指针
friend:友元
virtual:虚
delete、default:对类的特殊成员函数的相关使用
例如:Test(const Test &) = default; ~Test() = delete;
mutable:取消常属性
using:引入数据,有三种使用方式
i> 使用命名空间的关键字
ii> 相当于类型重定义
iii> 修改子类中从父类继承下来成员的权限
operator:运算符重载关键字
9> 类型转换相关的关键字
static_cast、dynamic_cast、const_cast、reinterpret_cast
10> 模板相关的关键字:template、typename
11> 命名空间相关:using、namespace
12> export:导入相关模板类使用
13> 内存分配和回收:new、delete
标准模板库中使用了大量的函数模板和类模板,来对数据结构和算法的处理。
STL主要由 容器、算法、迭代器组成。
容器:置物之所也
数组、链表、队列、栈、集合。。。
算法:问题之解法也
增、删、改、查
迭代器:是容器和算法之间的粘合剂 (== 指针)
类似于数组、也可称之为单端数组
和普通数组的区别:普通数组是静态空间,vector是动态拓展。
动态拓展:不是在原来空间后续接空间,而是重新申请更大的空间,将原来的数据拷贝到新的空间中。
vector的构造函数
vector v;//无参构造
vector(v.begin(),v.end()); //将区间[begin(),end()),拷贝给本身
vector(const vector& v); //将v拷贝给本身
vector(n, elem) ; //将n个elem拷贝给本身
#include
#include
using namespace std;
//算法
void printVector(vector &v)
{
vector::iterator iter; //定义了这样容器类型的迭代器
for(iter = v.begin(); iter != v.end(); iter++)
{
cout << *iter << " ";
}
cout << endl;
}
int main()
{
//容器
vector v; //无参构造函数
v.push_back(10); //尾插
v.push_back(20);
v.push_back(30);
v.push_back(40);
//算法
printVector(v);
vector v2(v.begin(),v.end());
printVector(v2);
vector v3(6,100);
printVector(v3);
vector v4 = v3;
printVector(v4);
vector v5(v2);
printVector(v5);
return 0;
}
vector的赋值函数
vector &operator = (const vector &v);//将v赋值给本身
assign(beg,end); //将区间[begin(),end())赋值给本身
assign(n, elem); //将n个elem赋值给本
vector容量大小
empty(); //判断容器是否为空
capacity() ; //计算容器的容量大小
size(); //计算容器大小 ---- 容器的元素个数
resize(); //重新设置大小
vector的插入和删除
push_back(); //尾插
pop_back(); //尾删
insert(iterator pos,elem) //在迭代器指向的位置,插入数据
insert(iterator pos,n, elem) //在迭代器指向的位置,插入n个数据
erase(iterator pos); //删除迭代器指向元素
erase(iterator start, iterator end); //删除区间的元素
clear() ; //删除容器中所有的元素
vector的元素提取
at(int idx);
operator[](int idx);
front(); //返回第一个元素
back(); //返回最后一个元素
由于程序运行时的数据都是历史数据,程序一旦结束,数据就会消失
头文件: #include
文件操作的三大类
读文件:ifstream
写文件:ofstream
读写:fstream
1.包含头文件
#include
2.创建流对象
ofstream ofs;
3.打开文件
ofs.open("文件名",打开方式);
4.写入数据
ofs
5.关闭文件
ofs.close();
1.包含头文件
#include
2.创建流对象
ifstream ifs;
3.打开文件
ifs.open("文件名",打开方式);
试编程:
封装一个学生的类,定义一个学生这样类的vector容器, 里面存放学生对象(至少3个)
再把该容器中的对象,保存到文件中。
再把这些学生从文件中读取出来,放入另一个容器中并且遍历输出该容器里的学生。
#include
#include
#include
#include
using namespace std;
class Stu {
private:
int classnum;
int grade;
string name;
public:
Stu() {}
Stu(int class_num, int grade, string name) : classnum(class_num), grade(grade), name(name) {}
void set(int i, int g) {
classnum = i;
grade = g;
}
void name_set(string n) { name = n; }
friend void ofs(vector& p);
};
void ofs(vector& p) {
ofstream ofs;
ofs.open("F:/test.txt", ios::out);
for (const auto& student : p) {
ofs << student.classnum << ' ' << student.grade << ' ' << student.name << endl;
}
ofs.close();
}
int main() {
vector p;
for (int i = 0, j = 1; i < 2; i++, j++) {
Stu student;
student.set(i, j);
if (0 == i) {
student.name_set("lisi");
} else if (1 == i) {
student.name_set("zhangsan");
}
p.push_back(student);
}
ofs(p);
return 0;
}
list相关函数
#include
#include
int main() {
// 默认构造函数
std::list lst1;
// 初始化列表构造函数
std::list lst2 = {1, 2, 3};
// 拷贝构造函数
std::list lst3(lst2);
// 填充构造函数
std::list lst4(3, 10); // 3个元素,每个元素都是10
// 赋值操作
lst1 = lst2;
// assign函数
lst1.assign({4, 5, 6});
lst2.assign(3, 7); // 3个元素,每个元素都是7
// 输出lst1
for (std::list::iterator it = lst1.begin(); it != lst1.end(); ++it) {
int x = *it;
std::cout << x << ' ';
}
std::cout<::iterator it = lst2.begin(); it != lst2.end(); ++it) {
int x = *it;
std::cout << x << ' ';
}
return 0;
}