C++学习整理
本帖最后由 bin554385863 于 2019-10-5 00:13 编辑一
*********************************************************
基础数据类型
有符号:
char
short
int
long int
long long int
float
double
long double
无符号:
unsigned char
unsigned short
unsigned int
unsigned long int
unsigned long long int
unsigned float
unsigned double
类型占用字节数及其最值:
#include <iostream>
#include <cmath>
#include <typeinfo>
#include <iomanip>
#include <string>
template <typename tp>
void min_max_Value(tp t)
{
const int _bit = 8;
const int _byte = sizeof(tp);
const long double MAX = (long double)pow(2.0, (_bit * (double)_byte - 1)) - 1;
const long double MIN = -(long double)pow(2.0, (_bit * (double)_byte - 1));
const long double unsignedMax = (long double)pow(2.0, (_bit * _byte)) - 1;
std::string _type(typeid(t).name());
if (_type == "e")
{
std::cout <<std::left<< "sizeof(" << typeid(t).name() << ") = " <<std::setw(3)<< (int)_byte << ""
<< typeid(t).name() << "_MAX = " << std::fixed << std::setprecision(0) << std::setw(35) << MAX
<< ""
<< typeid(t).name() << "_MIN = " << std::fixed << std::setprecision(0) << std::setw(35) << MIN
<< std::endl;
}
else
{
std::cout <<std::left<< "sizeof(" << typeid(t).name() << ") = " <<std::setw(3)<< (int)_byte << ""
<< typeid(t).name() << "_MAX = " << std::fixed << std::setprecision(0) << std::setw(35) << MAX
<< ""
<< typeid(t).name() << "_MIN = " << std::fixed << std::setprecision(0) << std::setw(35) << MIN << ""
<< "unsigned_Max = " << std::setw(25) << unsignedMax
<< std::endl;
}
// std::cout <<std::left<< "sizeof(" << typeid(t).name() << ") = " <<std::setw(3)<< (int)_byte << ""
// << typeid(t).name() << "_MAX = " << std::fixed << std::setprecision(0) << std::setw(35) << MAX
// << ""
// << typeid(t).name() << "_MIN = " << std::fixed << std::setprecision(0) << std::setw(35) << MIN << ""
// << "unsigned_Max = " << std::setw(25) << unsignedMax
// << std::endl;
}
int main(int argc, char const *argv[])
{
char c;
min_max_Value(c);
short s;
min_max_Value(s);
int i;
min_max_Value(i);
long int l;
min_max_Value(l);
long long ll;
min_max_Value(ll);
float f;
min_max_Value(f);
double d;
min_max_Value(d);
long double ld;
min_max_Value(ld);
long double ld;
min_max_Value(ld);
}
-------------------------------------------------------------------------------------------------------------------
sizeof(c) = 1 c_MAX = 127 c_MIN = -128 unsigned_Max = 255 //char
sizeof(s) = 2 s_MAX = 32767 s_MIN = -32768 unsigned_Max = 65535 //short
sizeof(i) = 4 i_MAX = 2147483647 i_MIN = -2147483648 unsigned_Max = 4294967295 //int
sizeof(l) = 4 l_MAX = 2147483647 l_MIN = -2147483648 unsigned_Max = 4294967295 //long int
sizeof(x) = 8 x_MAX = 9223372036854775807 x_MIN = -9223372036854775808 unsigned_Max = 18446744073709551616 //long long int
sizeof(f) = 4 f_MAX = 2147483647 f_MIN = -2147483648 unsigned_Max = 4294967295 //float
sizeof(d) = 8 d_MAX = 9223372036854775807 d_MIN = -9223372036854775808 unsigned_Max = 18446744073709551616 //double
sizeof(e) = 12 e_MAX = 39614081257132168796771975168 e_MIN = -39614081257132168796771975168
--typeid(t).name():输出变量t的类型;
--std::left:左对齐;
--std::setw(n):设置输出数据的宽度; #include <iomanip>
--std::setprecision(0):设置输出数据的小数位数;#include <iomanip>
-----------------变量/函数的存储类---------------------
---auto存储类:
所有变量和函数的默认存储类;
---register存储类:
register 存储类用于定义存储在寄存器中而不是 RAM 中的局部变量。这意味着变量的最大尺寸等于寄存器的大小(通常是一个词),且不能对它应用一元的 '&' 运算符(因为它没有内存位置)。
---static存储类:
->作用于局部变量时,局部变量的生命周期是整个程序的生命周期.静态局部变量只对定义自己的函数体始终可见;
->作用于全局变量时,全局变量的作用域被限制在声明它的文件内;
->全局声明的一个 static 变量或方法可以被任何函数或方法调用,只要这些方法出现在跟 static 变量或方法同一个文件中。
---extern存储类:
extern 存储类用于提供一个全局变量的引用,全局变量对所有的程序文件都是可见的。当您使用 extern 时,对于无法初始化的变量,会把变量名指向一个之前定义过的存储位置。
当您有多个文件且定义了一个可以在其他文件中使用的全局变量或函数时,可以在其他文件中使用 extern 来得到已定义的变量或函数的引用。可以这么理解,extern 是用来在另一个文件中声明一个全局变量或函数。
extern 修饰符通常用于当有两个或多个文件共享相同的全局变量或函数的时候
本帖最后由 bin554385863 于 2019-10-5 13:43 编辑
二
********************************************
---数学运算符(二元运算符)
加法运算符:+
递增运算符:++ ++a--先取值在递增;a++--先递增在取值.相当于a = a + 1;
累加运算符:+= a+=b相当于a=a+b;
减法运算符:-
递减运算符:-- --a先取值在递减;--a先递减在取值.相当于a = a - 1;
累减运算符:-= a-=b相当于a = a - b;
乘法运算符:*
累乘运算符:*= a*=b相当于a = a * b;
取商运算符:/
累除运算符:/= a/=b相当于a = a / b;
取余运算符:%
累余运算符:%= a%=b相当于a = a % b;
---关系运算符(二元运算符)
相等判定符:==
小于判定符:<
小于等于判定符:<=
大于判定符:>
大于等于判定符:>=
---逻辑运算符(二元运算符(特殊另外说明))
逻辑或:|| 一真则真;
逻辑非(一元运算符):! 真变假,假变真;
逻辑且(与):&& 一假则假;
选值运算符(三元运算符): a = c(二元逻辑运算符)b ? c: b 若c(二元逻辑运算符)b为真,则a = c,否则a = b;
---位运算符(二元)
左移运算符:<< 二进制左移指定位数;
左移赋值运算符:<<=;
右移运算符:>> 二进制右移指定位数;
右移赋值运算符:>>=;
位或运算符:| 一零得一;
位或赋值运算符:|=
位与运算符:& 一一得一;
位与赋值运算符:&=;
位反运算符(一元):~ 1变0, 0变1;
位异或运算符:^ 不同得一;相同得零;
位异或赋值运算符:^=;
---其他运算符
sizeof() 获取对象占用的字节数;
取址运算符&: 取得对象的内存地址;
解引用运算符*: 取得指针指向地址存储的的值;
&&右值引用运算符:引用右值;
成员运算符(点).成员运算符->(用于指针类型的对象);
域运算符::
*****************************************************************************************
三
********************************************************************************************
----自定义数据类型-----
#include <iostream>
#include <string>
//结构体
typedef struct a
{
int i;
std::string str;
} _struct;
//位域
typedef struct b
{
int i : 3;
int c : 5;
} _struct_;
//联合
union _union {
char *str;
int i;
};
//枚举
enum _enum
{
a = 1,
b,
c,
e,
k,
};
int main(int argc, char const *argv[])
{
//定义结构体变量
_struct arg0 = {100, "这是一个一结构体"};
std::cout << "_struct arg0 = {" << arg0.i << " , " << arg0.str << "}" << std::endl;
//定义位域结构体变量
_struct_ arg1 = {3, 10};
std::cout << "_struct_ arg1 = {" << arg1.i << " , " << arg1.c << "}" << std::endl;
//定义一个联合体变量,联合体一次只能使用一个数据,不能同时使用多个内部数据
union _union arg2;
arg2.str = "这是你一个联合体";
std::cout << "arg2.str = " << arg2.str << std::endl;
union _union arg2_0;
arg2_0.i = 230;
std::cout << "arg2_0.str = " << arg2_0.i << std::endl;
//定义一个枚举变量
enum _enum arg3;
std::cout << "enum _enum arg3 = {";
for (size_t i = a; i <= k ; i++)
{
std::cout << i << "";
}
std::cout << "}";
return 0;
}
-----------------------------------------------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-yj0v0dby.55c --stdout=Microsoft-MIEngine-Out-wqvz5s0e.kwx --stderr=Microsoft-MIEngine-Error-gfyirm3a.fkg --pid=Microsoft-MIEngine-Pid-jvt14vel.lfg "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
_struct arg0 = {100 , 这是一个一结构体}
_struct_ arg1 = {这是一个位域结构体 , 3 , 10}
arg2.str = 这是你一个联合体
arg2_0.str = 230
enum _enum arg3 = {12345}
E:\Users\86184\Documents\Code>
----强类型枚举----
使用enum class定义枚举,枚举值不会被隐式转换为整数;
语法: enum class var:type {...枚举成员...};
**************************************************************************************
四
*********************************************************************************************
-----分支-----
--if--else分支----
if(条件语句)
{
条件为真时执行语句块1
}
else
{
否则执行语句块2
}
---if--else if---
if(条件语句1)
{
条件为真时执行语句块1;
}
else if(条件语句2)
{
条件2为真时执行语句块2;
}
............
else if(条件语句n)
{
条件n为真时执行语句块n;
}
else
{
否则执行此语句块;
}
----switch分支----
switch (变量或者表达式)
{
case /*常量 */:
/* code */
break;
case /* 常量 */:
/* code */
break;
........
default:
break;//break的作用是跳出当前分支;
}
***循环***
----for循环----
for (size_t i = 0; i < count; i++)
{
/* 循环体 */
}
---范围for循环---
//范围for常用来操作数组元素或者其他容器类型的数据
.....
for(type i : 数组/容器)
{
std::cout<<i<<std::endl;
}
---while循环---
while循环是先判断后循环
while (/* 条件语句 */)
{
/* 循环体 */
}
---do---while循环----
dowhile是先循环后判断
do
{
/* 循环体 */
} while (/* 条件语句 */);
***break:立即跳出当前循环,一次只能跳出一层循环;
***continue:结束当前循环进行下一次循环;
本帖最后由 bin554385863 于 2019-10-5 14:39 编辑
五
****************************************************************************
------数组------
数组是一组类型相同得数据的集合;
一维数组
type arr;
二维数组
type arr:arr是一个含有x个元素为含有y个元素一维数组的数组;
---定义方式:
类型 数组名[数组大小];
//int var;
---初始化方式:
数组名[] = {数组元素已知};当已知数组元素已知时,可以不指定数组的大小;
//int var[] = {1,2,3,4,5};
数组名[数组大小] = {数组元素未知};当数组元素未知或已知其中几个时,必须指定数组大小;
//int var = {}
//int var = {1,2,} 部分初始化,其他元素都是0,部分初始化只能按照顺序来不能跳位;如 int arr = {1,"",2,}是错误的;
数组名[数组大小] = {0};所有的数组元素都是零;
#include <iostream>
//数组
int main(int argc, char const *argv[])
{
int var = {0};
//输出一维数组
std::cout<<"输出一维数组"<<'\n';
for(int i: var)
{
std::cout<<i<<" ";
}
std::cout<<std::endl;
int arr[] = {{0},{0},{1,2,3}};
//输出二维数据组
std::cout<<"输出二维数组第二维首地址"<<'\n';
for(int *i:arr)
{
//范围for只能用来操作一维数组,操作多为数组会导致错误
//用范围for可以输出二维数组第二维的首地址,即,二维数组的第一维是第二维的首地址
std::cout<<i<<std::endl;
}std::cout<<"输出二维数组元素"<<'\n';
for (size_t i = 0; i < sizeof(arr)/sizeof(arr); i++)
{
//正确用法是先遍历二维数组的是第一维
//再使用范围for循环操作第二维
for(int j:arr)
{
std::cout<<j<<" ";
}
std::cout<<std::endl;
}
return 0;
}
----------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-umtzvg5c.q1c --stdout=Microsoft-MIEngine-Out-rg25ikl0.eho --stderr=Microsoft-MIEngine-Error-bb34srhl.moo --pid=Microsoft-MIEngine-Pid-ksj0cn13.h04 "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
输出一维数组
0 0 0 0 0
输出二维数组第二维首地址
0x61fe9c
0x61feb0
0x61fec4
输出二维数组元素
0 0 0 0 0
0 0 0 0 0
1 2 3 0 0
E:\Users\86184\Documents\Code>
****特殊的字符数组****
char arr:大小加1是因为字符数组比其他数组多了一个结束符'\0';
//c++已经不需要这种操作了,C++会自动在字符数组初始化时在末尾加'\0',且大小也不用加1了;
#include <iostream>
int main(int argc, char const *argv[])
{
//第一种初始化方式
char ch[] = {'h','e','l','l','o',};
for(char c:ch)
{
std::cout<<c;
}
//第二种初始化方式
char c[] = " world";
for(char i:c)
{
std::cout<<i;
}
return 0;
}
------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-5vunpy5c.x5t --stdout=Microsoft-MIEngine-Out-hbztdrwh.iyr --stderr=Microsoft-MIEngine-Error-ueomfv1w.j0s --pid=Microsoft-MIEngine-Pid-aqo3kp1d.5q0 "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
hello world
E:\Users\86184\Documents\Code>
本帖最后由 bin554385863 于 2019-10-6 01:40 编辑
六
************************************************************************
---指针----
---指针变量保存的是一个内存地址;
---指针变量的定义:
变量类型 *变量名字
//char *ch;
---指针变量的初始化:
type *variablename = nullptr;
//将指针变量初始化唯一个空指针.
---指针指向一个变量的地址:
int var = 10;
int *ptr = &var;
//指针ptr保存的是var的地址.
//&在这里是取址符,表示取得var的内存地址.
#include <iostream>
//使用普通变量作为参数交换俩个整数
void _swap(int a, int b)
{
int t = a;
a = b;
b = t;
std::cout<<"("<<a<<" , "<<b<<")"<<std::endl;
}
//使用指针作为参数交换俩个整数
void _swap(int *a, int *b)
{
int t = *a;
*a = *b;
*b = t;
std::cout<<"("<<*a<<" , "<<*b<<")"<<std::endl;
}
int main(int argc, char const *argv[])
{
int a = 100,b = 200;
std::cout<<"普通参数"<<std::endl;
_swap(a, b);
std::cout<<"("<<a<<" , "<<b<<")"<<std::endl;
std::cout<<"指针参数"<<std::endl;
_swap(&a, &b);
std::cout<<"("<<a<<" , "<<b<<")"<<std::endl;
return 0;
}
-------------------------------------------------------------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-ke4xrign.g4b --stdout=Microsoft-MIEngine-Out-bjcgv0st.l14 --stderr=Microsoft-MIEngine-Error-3fh2qydp.j4g --pid=Microsoft-MIEngine-Pid-40mxpxvm.1p5 "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
普通参数
(200 , 100)
(100 , 200)
指针参数
(200 , 100)
(200 , 100)
E:\Users\86184\Documents\Code>
-----------------------------------------------------------------------
由上面的运行结果可以看出,
当形式参数是普通变量时,结果只在函数内部有效,出了函数就失效了;
当形式参数是指针变量时,结果出了函数依然有效.
指针可以随意指向任意一个位置,因此一个未初始化的指针是危险的,这样的指针称之为野指针,应该避免野指针的出现!
----指针和数组
数组的数组名相等于一个指针(不完全跟指针一样);区别是数组名作为指针是不可改变的;
因此对于一维数组:arr = *(arr + k);
二维数组:arr = *(*(arr + k) + j)
//这里吧arr作为指针
---特殊的字符数组也可以用指针定义,如:
char *ch = "hello";
不同的是指针定义的字符数组是一个常量数组.相当于const char ch[]= "hello";
且无法用范围for来操作指针定义的字符串;
#include <iostream>
int main(int argc, char const *argv[])
{
char *c = "hello";
for (size_t k = 0; k < 5; k++)
{
std::cout<<*(c + k);//相当于c
}
return 0;
}
------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-dxlos5rn.yb2 --stdout=Microsoft-MIEngine-Out-nnn3lcwo.dsv --stderr=Microsoft-MIEngine-Error-5a15v1ew.eor --pid=Microsoft-MIEngine-Pid-0wzfiqbo.2jm "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
hello
E:\Users\86184\Documents\Code>
本帖最后由 bin554385863 于 2019-10-7 11:51 编辑
七
************************************************
----自定义函数----
函数声明(有返回值):
返回值类型 函数名(形参列表);
函数定义:
返回值类型 函数名(形参列表)
{
函数体;
return 返回值;
}
-----------------------------------------------
函数声明(无返回值):
void 函数名(形参列表);
函数定义:
void 函数名(形参列表)
{
函数体;
//没有return语句;
}
#include <iostream>
int max(int a, int b)
{
//有返回值的函数
return a > b ? a : b;
}
void _swap(int &a, int &b)
{
//没返回值的函数,
int t = a;
a = b;
b = t;
}
int main(int argc, char const *argv[])
{
int a = 10, b = 100;
std::cout << "原数据" << '\n'
<< "a = " << a << '\n'
<< "b = " << b << std::endl;
std::cout << "最大值为" << '\n'
<< max(a, b) << std::endl;
_swap(a, b);
std::cout << "数值交换" << '\n'
<< "a = " << a << '\n'
<< "b = " << b;
return 0;
}
(int &a, int &b)表示参数是一个变量的引用,效果等同于指针;
不同的是指针是一个对象,而引用不是;指针可以改变指向,而引用不行;
引用是和变量绑定的.
------------------------------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-0v4irou2.n3l --stdout=Microsoft-MIEngine-Out-lu5e3moa.qjj --stderr=Microsoft-MIEngine-Error-11yrrpp2.fa2 --pid=Microsoft-MIEngine-Pid-aydf0r4r.2pa "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
原数据
a = 10
b = 100
最大值为
100
数值交换
a = 100
b = 10
E:\Users\86184\Documents\Code>
-------------------------------------------------------------------------------
自定义函数在文件开头定义时可以不声明;
后面才定义的函数一定要在文件开头声明.
=======================================================================
---函数指针
type function(args list)
{
function body;
}
type (*ptr)(args list)
ptr = function;//指向函数
也可以
type (*ptr)(args list) = function;//直接指向
//参数类型,和个数必须和指向的函数一模一样;
#include <iostream>
void _swap(int &a, int &b)
{
int t = a;
a = b;
b = t;
}
int main(int argc, char const *argv[])
{
int a = 41, b = 96;
void (*ptr)(int &a, int &b) = _swap;//定义一个函数指针
//ptr = _swap;//指向一个函数
std::cout << "原数据" << '\n'
<< "a = " << a << '\n'
<< "b = " << b<<'\n';
ptr(a, b);//使用指针调用函数
std::cout << "ptr(a, b)" << '\n'
<< "a = " << a << '\n'
<< "b = " << b;
return 0;
}
-----------------------------------------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-025q3y2h.vc5 --stdout=Microsoft-MIEngine-Out-15kpp1nx.a2o --stderr=Microsoft-MIEngine-Error-mnxxakk3.kbs --pid=Microsoft-MIEngine-Pid-b2csjtgi.mlv "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
原数据
a = 41
b = 96
ptr(a, b)
a = 96
b = 41
E:\Users\86184\Documents\Code>
---------------------------------------------------------------------------------------------------------------
----函数指针的作用不止可以用来调用函数,还可以作为函数的参数
/*函数指针*/
#include <iostream>
int max(int &a, int &b)
{
return a > b ? a : b;
}
void sum(int i, int j, int x, int y, int (*ptr)(int &a, int &b)) //函数指针作为参数
{
ptr = max; //指向函数
printf("%d + %d = %d", ptr(i, j), ptr(x, y), ptr(i, j) + ptr(x, y));
}
int main(int argc, char const *argv[])
{
int a = 41, b = 96;
int i = 52, j = 32;
int (*ptr)(int &a, int &b); //定义函数指针
sum(a, b, i, j, ptr);//传入函数
return 0;
}
-----------------------------------------------------------------------------------------------
E:\Users\86184\Documents\Code>c:\Users\86184\.vscode\extensions\ms-vscode.cpptools-0.25.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-aaj1q15x.ipf --stdout=Microsoft-MIEngine-Out-z1zinsyb.gc2 --stderr=Microsoft-MIEngine-Error-oiwb5cle.qm5 --pid=Microsoft-MIEngine-Pid-ptuabdxa.ueg "--dbgExe=E:\My Program\MinGW\bin\gdb.exe" --interpreter=mi
96 + 52 = 148
E:\Users\86184\Documents\Code> ********************************************************************
C++容器详解
https://en.cppreference.com/w/cpp/container
************************************************************************ 本帖最后由 bin554385863 于 2019-10-8 23:40 编辑
八
-----容器-----
C++容器整理
本帖最后由 bin554385863 于 2019-11-5 21:52 编辑
2019年11月5日20:20:52
函数模板
--->常规函数模板
template <typename ty>
void swap(ty &a, ty &b)
{
ty tmp = a;
a = b;
b = tmp;
}
--->显示实例化
template <typename ty>
template void swap<int>(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
--->显示具体化
template <typename ty>
template<> swap<int>(int &a, int &b)
{
int tmp = a;
a = b;
b = tmp;
}
--->当函数重载的版本中含有函数模板时:
swap<>(int a, int b)
表示指定使用模板函数
--->函数后置返回类型
auto func(type date....) -> returntype;用来解决参数类型不确定的模板函数 本帖最后由 bin554385863 于 2019-11-6 03:30 编辑
2019年11月6日02:46:39
/*
设计一个函数模板,对于非字符串数组,返回其最大值.
对于字符串数组,返回长度最长的字符串的地址.
*/
#include <iostream>
#include <vector>
#include <cstring>
template <typename ty, size_t count>
//内置数组版本
ty max(const ty (&arr)) //数组的引用
{
ty tmp = arr;
for (size_t i = 0; i < count; i++)
{
tmp = tmp > arr ? tmp : arr;
}
return tmp;
}
//可变数组版本
template <typename ty>
ty max(const std::vector<ty> &vec)
{
ty tmp = vec;
for (ty arg : vec)
{
tmp = tmp > arg ? tmp : arg;
}
return tmp;
}
//字符串版本
template <typename ty, size_t count>
char *max(char *const (&ptr)) //模板函数具体化
{
char *p = ptr;
for (size_t i = 0; i < count; i++)
{
p = strlen(p) > strlen(ptr) ? p : ptr;
}
return p;
}
int main(int argc, char const *argv[])
{
int arr[] = {1, 2, 3, 6, 54, 79, 99};
std::cout << "内置类型数组版本 :" << max(arr) << std::endl;
std::vector<float> vec = {3.14, 2.718, 3.163, 1.414, 2.236};
std::cout << "vector版本 :" << max(vec) << std::endl;
char *str = {"hello", "fish999999999", "ccc11111"," 000000000000000000000"};
std::cout << "C字符串版本 :" << max<char>(str) << std::endl;
return 0;
}
--------------------------------------------------------------------------------------------
Microsoft Windows [版本 10.0.18363.418]
(c) 2019 Microsoft Corporation。保留所有权利。
E:\Users\admin\Documents\VScode>c:\Users\admin\.vscode\extensions\ms-vscode.cpptools-0.26.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-sa0t0owb.i5f --stdout=Microsoft-MIEngine-Out-t0fvw4sd.ynd --stderr=Microsoft-MIEngine-Error-0dl1xzbo.3ne --pid=Microsoft-MIEngine-Pid-nehnila4.4e0 --dbgExe=D:\MinGW\bin\gdb.exe --interpreter=mi
内置类型数组版本 :99
vector版本 :3.163
C字符串版本 : 000000000000000000000
E:\Users\admin\Documents\VScode> 2019年11月7日21:30:44
new运算符
--->常规new运算符:
type *var = new type;//动态申请一个变量空间;
delete var;//使用delete释放申请的空间
type *var = new type ;//动态申请一个数组
delete [] var;//释放申请的动态数组空间
int *ditgit = new int {6};/动态申请一个变量空间并初始化为6;
int *array = new int {0}, 动态申请一个数组并把所有元素初始化为0;
--->定位new运算符:
type var1;//定义一个静态数组
type *var2;//定义一个静态数组
var2 = new (var1) //在var1的空间里面申请一个数组var2;
定位new运算符可以自定义申请空间的位置.
当依赖的空间是静态空间时,不能通过delete释放空间.
当依赖的空间是常规new申请的动态空间时,delete释放要从内而外 本帖最后由 bin554385863 于 2019-11-12 01:37 编辑
2019年11月12日01:30:56
转载自http://c.biancheng.net/view/2227.html
C++静态成员变量 >
对象的内存中包含了成员变量,不同的对象占用不同的内存(已在《C++对象的内存模型》中提到),这使得不同对象的成员变量相互独立,它们的值不受其他对象的影响。例如有两个相同类型的对象 a、b,它们都有一个成员变量 m_name,那么修改 a.m_name 的值不会影响 b.m_name 的值。
可是有时候我们希望在多个对象之间共享数据,对象 a 改变了某份数据后对象 b 可以检测到。共享数据的典型使用场景是计数,以前面的 Student 类为例,如果我们想知道班级中共有多少名学生,就可以设置一份共享的变量,每次创建对象时让该变量加 1。
在C++中,我们可以使用静态成员变量来实现多个对象共享数据的目标。静态成员变量是一种特殊的成员变量,它被关键字static修饰,例如:
class Student{
public:
Student(char *name, int age, float score);
void show();
public:
static int m_total;//静态成员变量
private:
char *m_name;
int m_age;
float m_score;
};
这段代码声明了一个静态成员变量 m_total,用来统计学生的人数。
static 成员变量属于类,不属于某个具体的对象,即使创建多个对象,也只为 m_total 分配一份内存,所有对象使用的都是这份内存中的数据。当某个对象修改了 m_total,也会影响到其他对象。
static 成员变量必须在类声明的外部初始化,具体形式为:
type class::name = value;
type 是变量的类型,class 是类名,name 是变量名,value 是初始值。将上面的 m_total 初始化:
int Student::m_total = 0;
静态成员变量在初始化时不能再加 static,但必须要有数据类型。被 private、protected、public 修饰的静态成员变量都可以用这种方式初始化。
注意:static 成员变量的内存既不是在声明类时分配,也不是在创建对象时分配,而是在(类外)初始化时分配。反过来说,没有在类外初始化的 static 成员变量不能使用。
static 成员变量既可以通过对象来访问,也可以通过类来访问。请看下面的例子:
//通过类类访问 static 成员变量
Student::m_total = 10;
//通过对象来访问 static 成员变量
Student stu("小明", 15, 92.5f);
stu.m_total = 20;
//通过对象指针来访问 static 成员变量
Student *pstu = new Student("李华", 16, 96);
pstu -> m_total = 20;
这三种方式是等效的。
注意:static 成员变量不占用对象的内存,而是在所有对象之外开辟内存,即使不创建对象也可以访问。具体来说,static 成员变量和普通的 static 变量类似,都在内存分区中的全局数据区分配内存。
下面来看一个完整的例子:
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
void show();
private:
static int m_total;//静态成员变量
private:
char *m_name;
int m_age;
float m_score;
};
//初始化静态成员变量
int Student::m_total = 0;
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
m_total++;//操作静态成员变量
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<"(当前共有"<<m_total<<"名学生)"<<endl;
}
int main(){
//创建匿名对象
(new Student("小明", 15, 90)) -> show();
(new Student("李磊", 16, 80)) -> show();
(new Student("张华", 16, 99)) -> show();
(new Student("王康", 14, 60)) -> show();
return 0;
}
运行结果:
小明的年龄是15,成绩是90(当前共有1名学生)
李磊的年龄是16,成绩是80(当前共有2名学生)
张华的年龄是16,成绩是99(当前共有3名学生)
王康的年龄是14,成绩是60(当前共有4名学生)
本例中将 m_total 声明为静态成员变量,每次创建对象时,会调用构造函数使 m_total 的值加 1。
之所以使用匿名对象,是因为每次创建对象后只会使用它的 show() 函数,不再进行其他操作。不过使用匿名对象无法回收内存,会导致内存泄露,在中大型程序中不建议使用。
几点说明
1) 一个类中可以有一个或多个静态成员变量,所有的对象都共享这些静态成员变量,都可以引用它。
2) static 成员变量和普通 static 变量一样,都在内存分区中的全局数据区分配内存,到程序结束时才释放。这就意味着,static 成员变量不随对象的创建而分配内存,也不随对象的销毁而释放内存。而普通成员变量在对象创建时分配内存,在对象销毁时释放内存。
3) 静态成员变量必须初始化,而且只能在类体外进行。例如:
int Student::m_total = 10;
初始化时可以赋初值,也可以不赋值。如果不赋值,那么会被默认初始化为 0。全局数据区的变量都有默认的初始值 0,而动态数据区(堆区、栈区)变量的默认值是不确定的,一般认为是垃圾值。
4) 静态成员变量既可以通过对象名访问,也可以通过类名访问,但要遵循 private、protected 和 public 关键字的访问权限限制。当通过对象名访问时,对于不同的对象,访问的是同一份内存。
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
C++静态成员函数 >
在类中,static 除了可以声明静态成员变量,还可以声明静态成员函数。普通成员函数可以访问所有成员(包括成员变量和成员函数),静态成员函数只能访问静态成员。
编译器在编译一个普通成员函数时,会隐式地增加一个形参 this,并把当前对象的地址赋值给 this,所以普通成员函数只能在创建对象后通过对象来调用,因为它需要当前对象的地址。而静态成员函数可以通过类来直接调用,编译器不会为它增加形参 this,它不需要当前对象的地址,所以不管有没有创建对象,都可以调用静态成员函数。
普通成员变量占用对象的内存,静态成员函数没有 this 指针,不知道指向哪个对象,无法访问对象的成员变量,也就是说静态成员函数不能访问普通成员变量,只能访问静态成员变量。
普通成员函数必须通过对象才能调用,而静态成员函数没有 this 指针,无法在函数体内部访问某个对象,所以不能调用普通成员函数,只能调用静态成员函数。
静态成员函数与普通成员函数的根本区别在于:普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
下面是一个完整的例子,该例通过静态成员函数来获得学生的总人数和总成绩:
#include <iostream>
using namespace std;
class Student{
public:
Student(char *name, int age, float score);
void show();
public://声明静态成员函数
static int getTotal();
static float getPoints();
private:
static int m_total;//总人数
static float m_points;//总成绩
private:
char *m_name;
int m_age;
float m_score;
};
int Student::m_total = 0;
float Student::m_points = 0.0;
Student::Student(char *name, int age, float score): m_name(name), m_age(age), m_score(score){
m_total++;
m_points += score;
}
void Student::show(){
cout<<m_name<<"的年龄是"<<m_age<<",成绩是"<<m_score<<endl;
}
//定义静态成员函数
int Student::getTotal(){
return m_total;
}
float Student::getPoints(){
return m_points;
}
int main(){
(new Student("小明", 15, 90.6)) -> show();
(new Student("李磊", 16, 80.5)) -> show();
(new Student("张华", 16, 99.0)) -> show();
(new Student("王康", 14, 60.8)) -> show();
int total = Student::getTotal();
float points = Student::getPoints();
cout<<"当前共有"<<total<<"名学生,总成绩是"<<points<<",平均分是"<<points/total<<endl;
return 0;
}
运行结果:
小明的年龄是15,成绩是90.6
李磊的年龄是16,成绩是80.5
张华的年龄是16,成绩是99
王康的年龄是14,成绩是60.8
当前共有4名学生,总成绩是330.9,平均分是82.725
总人数 m_total 和总成绩 m_points 由各个对象累加得到,必须声明为 static 才能共享;getTotal()、getPoints() 分别用来获取总人数和总成绩,为了访问 static 成员变量,我们将这两个函数也声明为 static。
在C++中,静态成员函数的主要目的是访问静态成员。getTotal()、getPoints() 当然也可以声明为普通成员函数,但是它们都只对静态成员进行操作,加上 static 语义更加明确。
和静态成员变量类似,静态成员函数在声明时要加 static,在定义时不能加 static。静态成员函数可以通过类来调用(一般都是这样做),也可以通过对象来调用,上例仅仅演示了如何通过类来调用。 非常感谢分享 万分感谢!支持!{:5_95:} 本帖最后由 bin554385863 于 2019-11-17 01:00 编辑
2019年11月16日22:19:39
类的简单学习
->友元
->类的静态成员
类的静态成员函数只能访问类的静态成员变量,
类的静态成员变量只能在类外初始化;
所有实例化的对象共用一个静态成员变量;
->运算符重载
#include <iostream>
class Circle
{
private:
double Radius; //半径
public:
static const double PI;
Circle(double r = 0) : Radius(r) //构造函数
{
}
Circle(const Circle &circle) //赋值构造
{
this->Radius = circle.Radius;
}
void setCircleRadius(double r) //设置半径
{
Radius = r;
}
double getCircleRadius() const //获取半径
{
return Radius;
}
double getCirclePerimeter() const //获取周长
{
return 2 * PI * Radius;
}
double getCircleArea() const//获取面积
{
return PI * Radius * Radius;
}
/*扩大倍数*/
Circle &operator*(int n)
{
static Circle circle;
circle.Radius = n*this->Radius;
return circle;
}
friend Circle operator*(int n, Circle &circle)
{
return circle*n;
}
friend std::ostream &operator<<(std::ostream &os, Circle &circle) //重载<<运算符
{
os << "CircleRadius: " << circle.Radius << "\n"
<< "CirclePerimeter: " << circle.getCirclePerimeter() << "\n"
<< "CircleArea: " << circle.getCircleArea() << std::endl;
return os;
}
~Circle() {}
};
double const Circle::PI = 3.141592653;
int main(int argc, char const *argv[])
{
Circle circle0, circle1, circle2,circle3;
circle1.setCircleRadius(5);
circle2 = circle1*2;
circle3 = 5*circle2;
std::cout<<circle0<<std::endl;
std::cout<<circle1<<std::endl;
std::cout<<circle2<<std::endl;
std::cout<<circle3<<std::endl;
return 0;
}
------------------------------------------------------------------------------
Microsoft Windows [版本 10.0.18363.476]
(c) 2019 Microsoft Corporation。保留所有权利。
E:\Users\admin\Documents\VScode>c:\Users\admin\.vscode\extensions\ms-vscode.cpptools-0.26.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-bq53flzb.pdd --stdout=Microsoft-MIEngine-Out-0ezshnul.zpd --stderr=Microsoft-MIEngine-Error-dzndlmdf.zut --pid=Microsoft-MIEngine-Pid-xianufj3.alm --dbgExe=D:\MinGW\bin\gdb.exe --interpreter=mi
CircleRadius: 0
CirclePerimeter: 0
CircleArea: 0
CircleRadius: 5
CirclePerimeter: 31.4159
CircleArea: 78.5398
CircleRadius: 10
CirclePerimeter: 62.8319
CircleArea: 314.159
CircleRadius: 50
CirclePerimeter: 314.159
CircleArea: 7853.98
E:\Users\admin\Documents\VScode> 本帖最后由 bin554385863 于 2019-11-17 13:54 编辑
2019年11月17日13:43:39
使用常量表达式关键字constexpr,可以在类内只接定义并初始化一个静态常变量;
#include <iostream>
class Circle
{
private:
double Radius; //半径
static constexpr double PI = 3.141592653;
public:
Circle(double r = 0) : Radius(r) //构造函数
{
}
Circle(const Circle &circle) //赋值构造
{
this->Radius = circle.Radius;
}
void setCircleRadius(double r) //设置半径
{
Radius = r;
}
double getCircleRadius() const //获取半径
{
return Radius;
}
double getCirclePerimeter() const //获取周长
{
return 2 * PI * Radius;
}
double getCircleArea() const//获取面积
{
return PI * Radius * Radius;
}
/*扩大倍数*/
Circle operator*(int n)
{
Circle circle;
circle.Radius = n*this->Radius;
return circle;
}
friend Circle operator*(int n, Circle circle)
{
return circle*n;
}
friend std::ostream &operator<<(std::ostream &os, Circle &circle) //重载<<运算符
{
os << "CircleRadius: " << circle.Radius << "\n"
<< "CirclePerimeter: " << circle.getCirclePerimeter() << "\n"
<< "CircleArea: " << circle.getCircleArea() << std::endl;
return os;
}
~Circle() {}
};
int main(int argc, char const *argv[])
{
Circle circle0, circle1, circle2,circle3;
circle1.setCircleRadius(5);
circle2 = circle1*2;
circle3 = 5*circle2;
std::cout<<circle0<<std::endl;
std::cout<<circle1<<std::endl;
std::cout<<circle2<<std::endl;
std::cout<<circle3<<std::endl;
return 0;
}
-----------------------------------------------------------------------------------------------
Microsoft Windows [版本 10.0.18363.476]
(c) 2019 Microsoft Corporation。保留所有权利。
E:\Users\admin\Documents\VScode>c:\Users\admin\.vscode\extensions\ms-vscode.cpptools-0.26.1\debugAdapters\bin\WindowsDebugLauncher.exe --stdin=Microsoft-MIEngine-In-h1lpdybk.tnm --stdout=Microsoft-MIEngine-Out-n3y0wogh.a1v --stderr=Microsoft-MIEngine-Error-10zvmj2h.5xb --pid=Microsoft-MIEngine-Pid-yatt0w1c.rzx --dbgExe=D:\MinGW\bin\gdb.exe --interpreter=mi
CircleRadius: 0
CirclePerimeter: 0
CircleArea: 0
CircleRadius: 5
CirclePerimeter: 31.4159
CircleArea: 78.5398
CircleRadius: 10
CirclePerimeter: 62.8319
CircleArea: 314.159
CircleRadius: 50
CirclePerimeter: 314.159
CircleArea: 7853.98
E:\Users\admin\Documents\VScode>
页:
[1]