C++工程实战入门笔记5-函数(二)
函数默认参数
//默认参数
void TestFuncDec(int x, int y = 200, int z = 300)
{cout << "TestFuncDec: " << x << "," << y << "," << z << endl;
}int main()
{TestFuncDec(100);TestFuncDec(100, 100);TestFuncDec(100, 100, 100);system("pause");
}
函数重载
//函数重载,函数同名,参数不同类型或者不同数量
void Test(int p)
{cout << "Test:" << p << endl;
}
void TestOverLoad(int x)
{cout << "int:" << x << endl;Test(x);
}
void TestOverLoad(float x)
{cout << "float:" << x << endl;if (x - (int)x > 0.5)x++;Test(x);
}
void TestOverLoad(double x,double y)
{cout << "double x y:" << x <<","<<y<< endl;Test(x+y);
}
int main()
{TestOverLoad(100);cout << endl;TestOverLoad(1.3f);cout << endl;TestOverLoad(1.6f);cout << endl;TestOverLoad(1.7, 2.3);cout << endl;system("pause");
}
使用默认参数:
函数基本行为相同,只是某些参数通常使用特定值希望保持代码简洁,减少函数数量参数有自然的默认值
使用函数重载:
不同参数组合需要完全不同的实现参数类型不同导致处理逻辑不同需要处理不同的参数数量且逻辑差异大
函数与数组和字符串
int main()
{char arr[10];//声明一个可以容纳10个字符的数组,但未初始化,内容是不确定的char str1[]{ "0123456789" };//包含11个字符的数组,编译器自动推导数组大小为11(10个字符 + 1个空终止符)const char* str2{ "ABCDE" };//指向常量字符的指针,使用const修饰符以确保不会意外修改字符串内容int datas[]{ 0,1,2,3,4,5,6,7,8 };//包含9个整数的数组,编译器自动推导数组大小为9cout << "arr:" << sizeof(arr) << '\t'<< "str1:" << sizeof(str1) << '\t'<< "str2:" << sizeof(str2) << '\t'<< "datas:" << sizeof(datas) << endl;//arr:10 str1:11 str2:8 datas:36//数组可以auto遍历,指针不可以for (auto d : datas){cout << d << '\t';}cout<< endl;//更改无效,d只是数组中元素的复制for (auto d : datas) d += 100;for (auto d : datas) cout << d << '\t';cout << endl;//更改有效,引用可以更改数组中元素值for (auto &d : datas) d += 100;for (auto d : datas) cout << d << '\t';cout << endl;system("pause");
}
返回数组只能是指针,数组参数全部变为指针
int* TestArr(char arr[10], char str1[], const char* str2, int datas[])
{cout << "arr:" << sizeof(arr) << '\t'<< "str1:" << sizeof(str1) << '\t'<< "str2:" << sizeof(str2) << '\t'<< "datas:" << sizeof(datas) << endl;return datas;
}int main()
{char arr[10];//声明一个可以容纳10个字符的数组,但未初始化,内容是不确定的char str1[]{ "0123456789" };//包含11个字符的数组,编译器自动推导数组大小为11(10个字符 + 1个空终止符)const char* str2{ "ABCDE" };//指向常量字符的指针,使用const修饰符以确保不会意外修改字符串内容int datas[]{ 0,1,2,3,4,5,6,7,8 };//包含9个整数的数组,编译器自动推导数组大小为9TestArr(arr, str1, str2, datas);//arr:8 str1:8 str2:8 datas:8system("pause");
}
也可以把
char arr[10];//声明一个可以容纳10个字符的数组,但未初始化,内容是不确定的
char str1[]{ "0123456789" };//包含11个字符的数组,编译器自动推导数组大小为11(10个字符 + 1个空终止符)
const char* str2{ "ABCDE" };//指向常量字符的指针,使用const修饰符以确保不会意外修改字符串内容
int datas[]{ 0,1,2,3,4,5,6,7,8 };//包含9个整数的数组,编译器自动推导数组大小为9
换成
vector<char> arr(10);
char str1[]{ "0123456789" };
const char* str2{ "ABCDE" };
vector<int> datas{ 0,1,2,3,4,5,6,7,8 };
完整测试vector
vector<int> TestVecStr(vector<char> arr,string str1,string str2, vector<int> datas)
{cout << "arr:" << arr.size() << '\t'<< "str1:" << str1.size() << '\t'<< "str2:" << str1.size() << '\t'<< "datas:" << datas.size() << endl; //.size()不计算\0的大小,只计算字符数量大小for (auto &d : datas) d += 10000;return datas;
}int main()
{vector<char> arr(10);char str1[]{ "0123456789" };const char* str2{ "ABCDE" };vector<int> datas{ 0,1,2,3,4,5,6,7,8 };auto res = TestVecStr(arr, str1, str2, datas);for (auto d : datas) cout<<d<<'\t';//datas内部没改...vector<int> string 不引用指针,会复制堆中数据cout << endl;for(auto d:res) cout << d << '\t';//datas返回值改了cout << endl;system("pause");
}
下面是怎么能vector不复制堆内容,直接改呢,加入引用
将:
vector<int> TestVecStr(vector<char> arr,string str1,string str2, vector<int> datas)
改成
vector<int> TestVecStr(vector<char> arr,string str1,const string &str2, vector<int> &datas)
完整代码
vector<int> TestVecStr(vector<char> arr,string str1,const string &str2, vector<int> &datas)
{cout << "arr:" << arr.size() << '\t'<< "str1:" << str1.size() << '\t'<< "str2:" << str1.size() << '\t'<< "datas:" << datas.size() << endl; //.size()不计算\0的大小,只计算字符数量大小for (auto &d : datas) d += 10000;return datas;
}int main()
{vector<char> arr(10);char str1[]{ "0123456789" };const char* str2{ "ABCDE" };vector<int> datas{ 0,1,2,3,4,5,6,7,8 };auto res = TestVecStr(arr, str1, str2, datas);for (auto d : datas) cout<<d<<'\t';//datas内部改了,cout << endl;for(auto d:res) cout << d << '\t';//datas返回值改了cout << endl;system("pause");
}
#pragma once 作用
防止同一个头文件在同一个编译单元中被多次包含,从而避免重复定义、重复声明等编译错误。
核心作用:头文件保护
想象一下这个场景:
- main.cpp 同时包含了 headerA.h 和 headerB.h
- 而 headerB.h 本身也包含了 headerA.h
- 这样一来,headerA.h 的内容在 main.cpp 中被包含了两次
如果没有保护措施,头文件中的函数声明、类定义等就会出现两次,编译器会报“重复定义”的错误。
#pragma once
就是用来解决这个问题的。你只需要在头文件的最开头加上它:
// 在 myheader.h 中
#pragma once // <- 就是这行// 头文件的实际内容
class MyClass {// ...
};
void myFunction();
在 #pragma once
出现之前,人们使用宏定义守卫来实现同样的功能:
// 传统的宏定义守卫方式
#ifndef MY_UNIQUE_HEADER_NAME_H_ // 如果没有定义这个宏
#define MY_UNIQUE_HEADER_NAME_H_ // 就定义它// 头文件内容...
class MyClass {// ...
};#endif // MY_UNIQUE_HEADER_NAME_H_ // 结束
现代 C++ 开发中,绝大多数情况下推荐使用 #pragma once。
使用 #pragma once
的情况:
你的项目主要使用 Visual Studio、GCC、Clang 等现代编译器(它们全都支持)。
你追求代码简洁和可读性。
你不关心极端的跨编译器可移植性(例如,要移植到一些非常古老的编译器上)。
使用宏定义
守卫的情况:
你编写的代码需要在非常古老或冷门的编译器上编译,而这些编译器不支持 #pragma once。
你的头文件可能通过符号链接被以不同路径包含,你需要确保万无一失。
最佳实践
1、现代项目标配:直接在头文件顶部使用 #pragma once。这是当前的主流做法,简洁高效。
#pragma once
// ... 你的头文件内容
2、兼容性要求极高的项目或库:如果你不确定使用者的编译环境,为了最大兼容性,可以使用两者结合的方式。编译器会智能处理,不会带来额外开销。
#pragma once
#ifndef MY_PROJECT_UNIQUE_NAME_H_
#define MY_PROJECT_UNIQUE_NAME_H_
// ... 头文件内容
#endif
多文件声明定义函数和全局变量
头文件(test.h)
#pragma once
//声明全局变量
extern int gcount;
//int gerr; //.h中不能出现定义变量//函数声明
int TestFunc(int index, int x, int y = 10);
cpp文件(test.cpp)
#include "stdafx.h"
#include "test.h"
#include<iostream>
using namespace std;
//全局变量定义
int gcount;
int TestFunc(int index, int x, int y)//在 C++ 中,函数的默认参数只能在函数声明中指定一次,通常在头文件中。在函数定义中再次指定默认参数会导致编译错误。
{cout << index << " " << x << ":" << y << endl;return 0;
}
主函数main
#include<iostream>
#include "test.h"
using namespace std;
int main()
{cout <<"gcount="<< gcount << endl;TestFunc(100, 600, 400);system("pause");
}
string字符串指针和vector之间的转换
将 const char*字符串 转换为 vector
int main()
{const char* cstr{ "测试const char*到vector" };//复制内容到vector,可以传递//内存开始地址和结束地址//使用加法运算符移动指针//每加1 移动1个类型大小的内容int size = strlen(cstr);//字符串长度,不包含结尾\0//一:数据开始的内存;二:数据最后内存的下一位// \0的下一位vector<unsigned char> data(cstr,cstr+size+1);cout << data.size() << endl;cout << data.data() << endl;system("pause");
}
将 char数组 转换为 vector
data.clear();
cout << "data.clear()" << endl;
char astr[]{ "测试数组到vector" };
data.assign(astr, &astr[sizeof(astr)]);
cout << data.size() << endl;
cout << data.data() << endl;
将 string 转换为 vector
string str{ "测试string到vector" };
data.clear();
cout << "data.clear()" << endl;
data.assign(str.begin(), str.end());
data.push_back('\0');
cout << data.size() << endl;
cout << data.data() << endl;
vector转换成string
//vector转换成string
string outstr(data.begin(), data.end());
cout << "outstr = " << outstr << endl;