/
...
/
/
[OLD]Code Language Model
Search
Try Notion
[OLD]Code Language Model
一.基础数据类型
基础数据类型
Java
🗒️Java字节表
类型
长度
默认值
Boolean
1Bit
false
Char
8Bit
'\u0000'(null)
byte
16Bit
(byte)0
short
16Bit
(short)0
int
32Bit
0
long
64Bit
0L
float
32Bit
0.0f
double
64Bit
0.0d
默认值仅在对象-实例变量时候会被赋予,其他时刻无默认值
C++
🗒️C字节表
类型
长度
默认值\字面量
Boolean(ISO C++加入)
1Bit
false
Char
8Bit
'\u0000'(null)
wchar_t
对应底层类型而变(underlying类型)
L'A' (L前缀)
char16_t
对应底层类型而变
u'A'(u前缀)
char32_t
对应底层类型而变
u'A'(U前缀)
可通过变为双引号转换为字面量数组
原始字面量
R"(...)" 或R"+*(...)*+"
byte
16Bit
(byte)0
short
(16Bit At Least)
(short)0
int
(At Least short)
0
long
(32Bit At Least)&&(At Least int)
0L
long long(可能不支持)
(64Bit At Least)&&(At Least long)
0LL
unsigened
...
...
float
32Bit at least
0.0f
double
45Bit at least && ≥ float
0.0d
e表示法...
标识符规则(基本原字符集)
int __a //编译器内部保留 int __A //同上 int _A //同上 int _a //全局变量保留
Copy
C++
支持扩展字符集用于标识符命名(通用字符名)
// \u[8个16进制] // \U[16个16进制] // 例 int \u00F6 ; cout << \u00F6
Copy
C++
类似转义序列,使用ISO10646/Unicode(一种通用编码名)
注意:通用编码名而非通用编码
常量
C++/C
#define A 50 符号常量
const int a = 50 const常量
可以使用命名空间
在标准C语言中类似变量(部分C编译器采用C++处理C),不能使用其声明数组,C++可
const指针
int a = 1 ; const int *pt = &a ; //普通变量赋给常量指针 //代表指针所指向的值不变 const int a = 1 ; const int *pt = &a //const量赋给const指针 合法 const int a = 1 ; int *pt = &a ; //const量赋给普通指针 不合法 //非要这么做的借助强制类型转换const_cast //同样的规则 //函数传参时 //若有一个const指针,传参时其形参必须也是const形式
Copy
C++
字面量规则:参照C++字节表
字面量类型确定
整形
除非有理由为其他值统一为int
根据后缀
10进制不带后缀以 int\long\long long为顺序
16进制不带后缀以 int\unsigned int\long\unsigned long\long long\ull为顺序
变量定义
C++
变量声明
定义声明:开始分配内存空间
Auto:用于复杂类型比如
std:vector<double> scores ; auto pv = scores.begin() ;
Copy
C++
引用声明:使用其他位置定义的变量
初始化
运算符
关系运算符
赋值运算符
逻辑运算符
位运算符
造型(Cast)运算符
C++
发生条件:
函数传参\返回
赋值
常规赋值
{}{} 列表初始化,赋值(C++11):不允许限缩
表达式运算(UpCast)
显式强制类型转换
其他单目运算符
C++/C
++ --
单目前缀运算符++ — * & 结合性从左向右 例: *++a++*
单目后缀运算符++ — [] 结合性从左向右 例: a++—++
总统上,越靠近操作数的越先计算,并且先后缀优先级比前缀高(解释了*p[10] 不加括号后仙鹤[] 结合)
重载运算符
插入运算符
C++
count << "Hello World" ;
Copy
C++
将字符串发送给count,由于有运算符重载(面向对象的特性),可以“智能”判断发送的类型,并作出不同操作
比如
int carrot = 5 ;count << carrot ;
Copy
C++
二.复合类型
C++
数组
采用列表初始化{}:不允许限缩
不检查下标
常见初始化写法
数组名称等价于数组第一个元素的地址,而非数组的地址(可能仅解释为指针运算有效?)
short things[] = {1, 2, 3, 4} ; int num_elements = sizeof(things) / sizeof(short) ; //注意如果遗漏值,编译器可能不会为你检查出来,有风险,最好手动指明数组数目 //手动指定数组长度也可将多余长度留作他用
Copy
C++
sizeof为数组长度,strlen()为字符串长度,素组长度至少需要strlen()+1
C Style 字符串
需要'\0' 作为结尾
字符串字面量可通过 空格进行拼接
C++ 原生字符串(ANSI/ISO C++ 98)
位于<string> 库中, std命名空间中
视作简单类型(字符串变量赋值传递时按值传递)
定义时创建长度为0的对象,长度可动态改变
与C Style类似之处
可用字符串字面量初始化
可用cin/cout 但目前所学仅限最简单的形式(利用<< >>)(成员函数暂时不知可用否)
结构体
共用体(union)
枚举
匿名枚举:相当于创建符号常量,从0开始
显示设定枚举值:enum bits{one=1, two=2}
枚举量参与算术表达式时转换为int,但不能直接将int赋值给枚举值,可用强制类型转换
域内枚举(C++扩展)
vector模板
类似string类,一种动态数组,底层使用new和delete,但是是自动完成的
include <vector>
初始长度为0,可通过 vector<typeName> VarName(Size) 定义初始长度
支持 列表初始化 同类拷贝初始化(区别于同类引用初始化)
支持 函数化初始化
vector<int> a(7) ; //初始化7个元素,值为0; vector<int> a(7,3) ; //初始化7个元素,值为3;
Copy
C++
array模板
介于vector和数组之间,静态分配,开销小,但是可以 同类拷贝初始化(赋值按值传递)
和vector模板一样支持.at() .begin() .end() 成员函数
.at() 和 数组索引[]的区别在于 .at() 检查出界,开销更小
三.引用类型
C/C++
简单指针
//*结合性解释问题 int* a ; //解释:类型为int* int *a ; //解释:*a等价int 由于 int *a , b ; a为指针,b为int,故解释其二比较合理
Copy
C++
整数不能直接被赋值给指针
可通过new分配动态内存区域(heap),而非静态(heap),必须配对delete
可进行指针运算:+1,不是绝对地址+1,而是当前指针类型的下一个位置
new delete规则
非new分配内存,不要用delete释放
不要对同一内存释放两次
对空指针delete时安全的
对于数组而言,new[]时也应该delete[](无需带具体的delete[num])
对实体而言,new[]时应该delete
数组名—-指针
多数情况下数组名等价数组第一个元素的地址 比如 int a[] = {1, 2, 3} ; int *b = a ; 可知 a[1]==b[1] ; *(a+1)==*(b+1) ; 但是sizeof中数组名不会被解释成地址: 详见<.复合类型-C++-数组-Comment> 在对数组名取地址时,也一样,取地址会得到整个数组的地址(类型为int[])
Copy
C++
数组(的)指针 , 指针(的)数组
int a[10] ; 则有 int (*b)[10] = &tell ; //数组指针int *b[10] // 为指针数组
Copy
C++
引用类型
必须在定义时初始化,且不能更改,相当于创建变量的别名
传参时,必须传达变量本身,而不能是表达式(禁止临时变量)
若声明为const的话,可以传达表达式(可以新建临时变量),并在需要的时候新建临时变量 按值拷贝
引用的函数返回
注意不要返回临时变量
const引用返回:引用返回值是左值 可写出类似fun1(a,b)=1 的语句 若不想要修改(类似右值的特性),可加const
四.循环语句
C++
for语句
标准格式 for ( initialization ; test-expression ; update-expression ) {body}
为了实现如下写法,而改成了for(for-init-statment ; expression)
for( int i = 0 ; i < 5 ; i++ ); //在init部分完成初始化 注意:旧的实现可能将i移除循环声明,即循环结束后i未被销毁
Copy
C++
foreach 基于范围的for(C++11)
int a[5] ; for(int x : a) {body ;} //x为数组的第一个元素,而后依次迭代到最后一个 //问题:如何检测数组的边界?
Copy
C++
顺序和副作用
以往一个顺序点表示之上的副作用全部完成,; 即是一个顺序点
副作用: ...... 略
为了多线程改用顺序描述而非顺序点
五.分支语句
五.函数
函数格式
C++
函数定义:提供了函数的编译代码
函数头
函数体
函数原型:使得编译器知道函数的返回值和参数列表,有两种方法为文件提供原型
源文件中手动输入
头文件包含
可变参数原型需要明示如void function(...) ANSI C中可变参数的原型可以写成void funtion()void参数一样
作用:告诉参数列表,告诉返回值(接口)
也只需要函数接口信息—-故可以省略参数名称
void function(int , double) 合法
🤔:为何不从函数定义中获取这些信息
效率不高:搜索时暂停编译
可能位于其他文件中:编译时可能无权访问,在链接的时候才能凑出完整程序
函数默认值
通过原型告诉,而非定义
若要为某个形参指定默认值,其右边形参也必须指定
传递参数时,实参要从左到右依次键入,不可中间跳跃,有默认值的可省略
编译指令using
参数传递
形参列表:/-简单变量/-数组形参/-指针形参/-结构形参
简单变量
按值传递,强制转换
流程:先新建一个自动变量—-拷贝值—-退出函数后销毁
数组
传递的是指针而非数组名
int a[3] = {1, 2, 3} ; void fun1 (int b[]) { b[1] == 1 ; //可以像正常数组使用 sizeof(b) == 4 ; //sizeof结果是指针的大小为4 而非sizeof(a) == 12 }
Copy
C++
const int a[] 等价于 const int *a
结构体
按值传递
由于类对象基于结构体,故模板类(vector array)也是按值传递,string类也是
const返回比较
常规
引用
在cout示例中,返回自身可以写出串联表达式
const 引用
减少开销,如果有引用传入,此项最佳,常规按值返回的的量也为不可修改的值
但是不能返回临时变量(会被销毁)
const 常规
为避免写出epr1 + epr2 = var1
epr1+epr2会返回的临时对象,理应不可修改,故加const
函数指针
|-简单函数指针-|-函数指针数组-|
//简单定义初始化 int fun1( int a ) {...} ; int (*pf1)(int) = fun1 //简单声明加初始化 //区别函数调用和函数地址 函数调用为fun1(...) //指针调用 pf1(4) ; //或 (*pf)(4) ;
Copy
C++
简单声明调用:如上
函数指针(指针返回值)—-函数指针数组:如下
//先定义一个指针返回函数 double *fun2 (double a, double b) {...} ; //则对应函数指针 double *(*pf2) (double, double) = fun2; //将标识符替换成(*pf2)即可 //函数指针数组 double *(*pf2[3]) (double, double) = fun2; //[3]先结合说明是数组,其余部分说明类型 //还可新建指向函数指针数组的指针 auto pf3 = & pf2 //或者手写 //同样将标识符替换 double *(*(*pf3)[3]) (double, double) = & pf2 ;
Copy
C++
内联
无跨文件访问,只能单一文件访问(每个文件都必须定义)
所以一般放置于头文件中
在原来原型声明的地方完成定义(类似小函数的写法)
函数特性
C++
重载
根据函数的特征标(形参)进行重载
不区分const和非const 不区分引用和原始
返回值可以不同,但特征标也必须不同
重载解析
解析过程
创建候选列表—-同名的函数或模板及其重载
创建可行参数列表—-完全匹配>提升匹配(int→long)>标准匹配(int→char/long→double)
确定是否有可行函数
对于完全匹配也可有某些无关紧要的匹配
无关紧要匹配列表
实参—|—形参 Type <--> Type & Type --> const Type Type --> volatile Type Type[] --> Type *
Copy
C++
若完全匹配,则非模板>模板
若完全匹配均为模板函数,则较为具体的优先(显式具体>隐式实例)
多参数则跟脚麻烦此处不赘述
decltype
//例一 int x ; decltype( x ) ; //为int //例二 int a ; decltype( (a) ) ; //为int&
Copy
C++
语法decltype( expression )
若为无括号标识符则和标识符类型相同
若为函数调用,则和返回值相同
左值,则为其引用—→带括号标识符,则为引用
前面都不满足,则为expression的类型
模板函数是占位声明
由于模板,可能存在无法判断返回值的类型
可用auto占位,后置类型声明
template<typename Type1, typename Type2> auto fun1 (Type1 var1,Type2 var2) -> decltype(var1+var2) { ... }
Copy
C++
函数模板
简单模板的定义声明调用
template <typename AnyType> void Swap( AnyType &a, AnyType &b ) //原型 int main() { int i = 1 , j = 2 ; Swap(i,j) ; //隐式实例化 } template <typename AnyType> void Swap( AnyType &a, AnyType &b ) //定义 { AnyType temp ; temp = a ; a = b ; b = temp ; return ; }
Copy
C++
重载模板函数
可以混用未定义类和已知类,仍然通过特征标区别
template <typename AnyType> void Swap(AnyType &a, AnyType &b, int n){...};
Copy
C++
显示具体化—-显示实例化
//具体化(重写模板) template <> void Swap (int &a, int &b) ; //原型 //或---<job>可选 template <> void Swap<job> (int &a, int &b) ; //原型 //实例化(区别隐式实例化) template void Swap<job> (int &a, int &b) ; //原型
Copy
C++
五.内存模型
C++
inclue/cpp文件问题
📂include包含内容
函数原型
#define符号常量
类/结构声明
模板声明
内联函数(包括类内联)
📂cpp包含内容
所有声明对应的函数定义(除了内联)
单定义规则
不要用include包含cpp会导致多重定义 C++仅允许定义一次
IDE中,不要将项目文件包含.h文件
使用#ifndef...来防止.h文件被引用两次
对于外部变量/函数采用extern来引用声明,避免重复定义
作用域/链接性
定义:链接性表示标识符能否在不同文件中共享
外部:可在文件间共享 ——-无前缀函数外定义变量和无前缀函数
内部:只能在当前文件中访问
无链接性:只能在当前代码块访问()
语言间链接性
比如C++要调用C中函数,由于编译器内部实现不同,同名函数的内部函数名也不同
可通过 extern "C" void fun1(...) extern "C++" void fun2(...) 来准确调用和链接
变量/函数持续性—-作用域
自动持续性
范围:函数中声明变量(1种)
意义:在定义时候被创建,函数或代码段结束后销毁
作用域持续时间都在代码块内部
嵌套代码块时候,同名标识符时,隐藏相对外部的
register在C++中仅用作自动声明的显式关键字,无优化方面意义
auto 用作显式自动声明意义取消,另作他用
静态持续性
范围:函数外定义变量和使用static 的关键
无前缀函数外—外部链接性
static 函数外—-内部链接性
static 函数内—-无链接性
💡
区别自动变量,虽然作用域相同,但是持续性不同,一个立马被销毁,一个一直持续
意义:整个程序过程中一直存在
对于静态变量,如果没有手动初始化,则系统自动初始化为0
动态
分配时候创建,直到手动销毁
new手动分配,在堆(heap)中
由new delete 控制,不受作用域规则控制
(但用于跟踪的指针是受控的)
故可在一个函数中创建,另一个函数释放
定位new运算符
myclass *a = new(buffer) myclass(5) ; 其中new([address]) 就是定位new运算符
不能被和delete搭配使用,要销毁对象时候需要显式调用析构函数如a->~myclass
限定符
volatile
意义:可能有外部因素(非程序),改变变量的值
功能:不对其进行优化
mutable
对于const类对象,其某个成员依旧可以改变
const
虽然是说明符,但是对链接性有影响
const int a = 50 默认内部链接性 等价于static const int a = 50
要使其有外部链接性,定义时加入extern 比如extern const int a = 50
命名空间
空间:声明区域>潜在作用域>作用域
声明区域:
某种存储加链接性的变量类型其声明区域是固定的
有文件内和代码块两种
保证了不同声明区域,不会冲突
潜在作用域:其有可能作用域为定义到声明区域结尾
作用域:在潜在作用域中很可能被隐藏,剩下的即为变量作用域
名称空间
可以自己定义新的声明区域,并命名它
using声明
将特定名称加入本名称空间,就像在该名称空间声明一样
不允许同名变量/函数
using编译
像每条语句都加入域解析符号:: 一样
同名时,局部的会把using编译(相对外部)的隐藏
有可能造成错误而编译器不警告
六.OOP
Universal
对象/类
封装和隐藏数据
多态
继承
代码复用
C++
类的组成
类声明:成员变量,成员函数的声明(放于头文件)
类方法定义:成员函数的实现(放于cpp文件)
类内联:定义在类声明内的函数默认为类内联,当然,也可通过inline在类声明外定义(必须在同一文件中)
访问控制
private
默认访问控制符—不加任何访问控制符即为private
同类不同对象也可访问private成员
public
protected
定义类成员时使用域解析运算符:: 调用类成员时根据情况使用直接成员运算符. 间接成员->
const类
由于const类对象所有成员不能修改,其不能调用其成员函数
所以在进行类成员函数调用时,必然会涉及隐式的参数传递,若为const对象 则该隐式传递要保证不修改const对象的内容
通过类似 void show() const 的语法来保证
构造函数—-析构函数
当初始化类对象时自动调用构造,删除时自动删去
调用方式/初始化类型
//显式 Stock var1 = Stock(1,2) ; //隐式,初始化列表,单参数时也可直接赋值 Stock var1 = {1, 2} ; //动态存储 显式 Stock *var1 = new Stock(1, 2) ; //对象数组初始化 Stock var1[3] = { Stock(1, 2), Stock(1, 2), Stock(1, 2) } //对象数组初始化(列表初始化形式) Stock var1[3] = { {1, 2}, {1, 2}, {1, 2} }
Copy
C++
列表初始化一定要和某个构造函数相匹配
默认构造函数,
当并没有初始化时候,自动调用默认构造函数,其函体为{ } 等于不做任何事
要修改默认构造函数可以重载一个无参数的构造函数或者有所有参数都有默认值(只能有一个)
复制构造函数(参数为同类的构造函数)
函数传参时,同类初始化时,函数返回时会调用(新建临时变量),但部分情况下不会新建临时变量(const或引用)
默认为浅复制,一定要重载为深复制
如果不进行深复制,则会出现两个变量指向同一个对象的情况,假设一个是临时变量,销毁时,调用析构,则剩下哪个变量的内容会被破坏
类常量
由于类定义中const常量只有在对象创建才创建,且无法被所有对象共享
由于不在类中不能通过成员运算符.访问,需要通过作用域解析运算符::
枚举方法
我们可以声明枚举来变相声明常量,在需要的地方会化为整型
由于不真的创建枚举量,只是借用其符号定义,也可声明为匿名枚举
枚举类方法
//避免枚举符号定义重复比如 enum a { c=10, d=20 } ; enum b { c=10, d=20 } ; //invalid //可通过类枚举 enum class a { c=10, d=20 } ; enum class b { c=10, d=20 } ; //使用时 a var1 = a::c ; b var2 = b::c ; //但是注意,该枚举不会自动转换整型,需要显式转换 //比如: int(a::c)
Copy
C++
类初始化
成员列表初始化
当类成员含有const对象或被声明为引用时,必须在创建时初始化
而析构函数函数体中,所作的都是创建后工作,故不能给const量赋值
需要借助成员列表初始化
class myclass { private: const int a ; ... } myclass::myclass(int b) : a(b) {...}
Copy
C++
仅在构造函数中该语法有效
初始化顺序为其声明的顺序,而不是初始化排列的顺序
运算符重载
语法operateor[op](parament) 比如operateor+()
重载限制
不能新建运算符
不能重载标准运算符(两个操作数至少有一个是用户定义的,比如不能重载int+int)
赋值= 函数调用() 下标运算[] 间接引用-> 仅支持通过成员函数重载
五则运算+-*/% 和对应自操作运算符+=... 逻辑运算>=< 动态分配运算符new delete new[] ... 可重载
友元函数
可以访问private成员
在类声明中加入friend 关键字的函数
虽然在类声明中但不是成员,不适用成员运算符.
对于友元重载,需要传递两个操作数,对于非友元而言,其中一个通过this指针
比如operator+(int a, myclass b) operator+(int a)
赋值运算符重载
在赋值时调用
写法上同复制构造函数类似,但有几点要区别
目标对象可能已分配了数据,要使用delete[]来删除以前的数据
避免将对象赋给自身,否则在完成赋值前,可能析构函数已将数据释放
返回一个指向对象自身的引用return *this 原型为自身引用 MyClass &
对于初始化而言,时候调用取决于语法,有可能仅调用复制构造,也有可能调用复制构临时变量,然后将其赋值给新建变量
MyClass a ; MyClass b = a ; //赋值初始化,根据实现可能使用赋值运算符重载,但一定会调用复制构造 MyClass b = MyClass(a) ; //显式调用复制构造 MyClass b(a) ; //另一种初始化
Copy
C++
对于非同类赋值重载,可提升效率
对比如下
类的类型转换
其他类→本类
根据构造函数是否有提供其他类的构造函数吗
是否其他类能够自动类型转换成有提供的构造函数<关联函数重载解析>
可通过explicit 禁用隐式的自动转换
本类→其它类
特殊函数,转换函数operateor typename()
可以在本类的public中声明如
class A { private: ... public: operateor int () const ; operateor double () const ; }
Copy
C++
如果存在二义性,比如可转换为double int,而cout都可以接受,需要显式转换,自动转换会被禁用
七.类继承
C++
初始化
由于必须先创建基类成员,且继承类不能访问基类的私有成员,故在成员列表初始化中调用基类构造函数
若无显式调用,则调用默认的构造函数
myinherit::myinherit() : mybase() {...}
Copy
C++
💡
辨析: 同含有对象的成员列表初始化不同,其是采用对象名来进行列表初始化, 而此处则是采用基类类名来成员列表初始化
对析构同理,对象过期时,先析构基类再析构继承类
单向同类引用
基类的指针或者引用可以不显性转换的指向继承类(is a特性)
但是继承类指针或引用不能指向基类(单向)
抽象基类
至少有一个纯虚函数的类称为抽象基类
不能被单独创建
纯虚函数语法 virtual double fun1() = 0 函数原型后加入=0
但是纯虚函数可以有其定义,供继承类不重新定义时使用
多态
同一方法再基类和继承类表现不同(区别于重载)
已重定义的方法,如果想要调用基态的方法,用:: 即可
派生类的隐藏
若重定义则以函数名作为唯一指标来隐藏基类
意味则基类同名重载函数,若继承类多态一个,所有重载均会被隐藏
即要重定义所有的基类重载函数
直接重定义:根据引用变量的或指针的类型,来改变调用的方法
虚函数:根据对象的看法,来改变调用的方法
原理:通过保一个隐藏成员,保存虚函数表→动态联编(有开销→不默认的原因)
若一个方法是虚函数,其继承的同样为虚函数,不论继承类有无加virtual 关键字
虚析构
一定是必须的
原因:考虑一个这样情形继承类被基类引用,若无虚析构,则按基类方式销毁(内存溢出)
protect关键字: 继承类依旧可以访问,但外部不行
私有继承(has a关系)
不加任何限定词默认为私有继承,需要pubic来保证是公有
基类的共有保护成员成为继承类的私有成员
🤔如何访问内部继承的基类对象?
通过将自身强制类型转换为基类
//如 const mybase & myinherit::baseclass() const {return (const string &)*this }
Copy
C++
在私有继承中,不经过显式转换,不会自动将派生类引用或指针赋给基类的引用和指针
多重继承(Multi )
有几个继承类就继承几个基类对象,如上图,inherit有两个base对象
这将使得派生类基类指向发生错误,如base * p = &inherit 会具有二义性
通过强制类型转换解决base * p = level1_1(&inherit)
虚基类
level_1和level_2继承base时引入virtual关键字,派生时只会保存一个base对象
本质上是对virtual关键字的重载,和虚函数无关,避免新引入关键字对过往代码产生了错误?
过往的层层传递的成员列表初始化不起作用
避免level_1,level_2同时传递给base
如果有间接虚基类,则必须显式调用虚基类的构造函数,或者只使用默认构造函数
必须穿透调用: inherit::inherit(): level_1() , level_2() , base(){...}
改变二义性
二义性与访问规则无关,即使在private中,也会导致二义性
非虚基类中,若继承两个同名成员,则一定要使用域解析
虚基类中,派生类则优于直接先祖或间接先祖名称
例如:level_1(虚继承base)中和base中有同名函数 fun1
则inherit中无须限定词,也可使用level_1 中的fun1
别名
旧式typedef
using =,为模板建立别名
template <typename T> using arrtype = std::array<T,12> //则有 arrtype<int> var1 //等价于 std::array<int,12>
Copy
C++
八.类模板
C++
类模板声明头
template <typename Type> class Stack { private: Type a ; ... public: bool isempty() ; ... } //成员函数也用模板替代 //域解析必须为模板,故所有成员函数均为模板函数 template <typename Type> bool stack<Type>::isempty(){...} ;
Copy
C++
成员模板
在模板类中创建模板类型
将模板用作成员
template <template <typename T> thing > class crab { private: thing<int> a; ... } //根据传入的模拟来决定thing的类型
Copy
C++
模板类可继承,可嵌套,可递归
递归:myclass< myclass<int, int>, int >
实例化 具体化
同模板函数...略
template <class T1, int>...可以实现部分具体化
模板参数-|-类参数
template <template <typename T>class thing1, typename thing2 > //前者,传入一个模板,后者传入一个类 //thing1<int>中thing1被替换为我们传入的模板 //thing2 被替换为我们传入的类
Copy
C++
模板类友元函数
非模板:仅在类中以函数形式声明友元,需要在类外逐个定义重载
约束模板:类外定义函数模板,在类中声明函数的具体化
非约束模板:在类内定义模板,所有改模板的实例化都视作友元
八.标准IO
Universal
EOF问题
EOF(End of file)问题是一个文件问题
但是很多终端支持用文件重定向输入流,即文件模拟键盘 故写代码时候最好以文件标准为准 故需要用键盘模拟文件的End of file
Windows下为Crtl+Z Unix为Crtl+D
非Win原生的编译器也可识别Crtl+Z,但需要紧接一个回车(GUN C++ VC++ Borland)
C
scanf
Copy
C++
string.h(cstring)
strlen(str) ; /*------------*/ strcpy(str1,str2); //str2复制到1 strcat(str1,str2); //str2附加到1 strncpy(str1,str2,str1Szie); //str2复制到1,安全带边界版本 strncat(str1,str2,str1Szie); //str2附加到1,安全带边界版本 /*------------*/ strcmp(str1,str2) //相同返回0 //str1在str2之前返回负数 //str1在str2之后返回正数
Copy
C++
type.h(ctype)
isaplha(ch) //是否是字母(a-z和A-Z) isdigit(ch) //是否数组 ispunch(ch) //是否是标点 isalnum(ch) //是否字母加数字
Copy
C++
C++
cout
cout << Var_Or_Constvar ; //用例1 cout << "ABC" ; << Var ; //用例2 cout << "ABC" ; cout << Var ; //用例3 wchar_t bob = L'P' ; wcout << L"tall" << endl
Copy
C++
会根据<< 后的数据类型智能重载
支持转义符号
仅适用于普通类型,若要处理wchar_t类型,需要wcin\wcout
成员函数
//用例1 cout.put('A') ;
Copy
C++
cout.put(cahr)
cin
cin >> Var ;
Copy
C++
C++将cin/cout 定义为流对象<< 为插入输入流>> 为抽取流
以空白(空格 回车 制表符)作为结束符号
对比scanf
是否保留结束符号于输入流中?
忽略前导空格?
成员函数
//例一 cin.getline(name,20) ; //将输入读入到具有20个大小的name数组中(最大为19个字符) //例二 cin.get(name,20).get() ; cin.get(...)返回的还是cin对象 //例三 //直接原始输入 while(cin.fail()== false) { count++ ; cin,get(ch[count]) ; } //Or while(!cin.fail()) //当cin出现在需要bool值时默认等效替换上述函数 //故有Or while(cin) //由于cin.get返回cin对象 //固有Or while(cin.get(ch)){...}
Copy
C++
cin.getline([char_array],chSize) :仅使用回车作为结尾,读取并替换回车符
读取满后也会结束程序,设置失效位
cin.get([char_array],chSize) :类似getline,但是保留回车符在缓冲区
无参数下,可强制单独读取一个字符(即使是回车)
🤔为何传参可以传变量本体,不是形参么?—-可以将函数声明为引用类型传递
读取空行后,设置失效位并截断之后输入
但是对空格而言(非换行),会跳过前导空白(空格 制表)
检测到eof后failbit和eofbit会置1,可通过成员函数cin.eofcin.fail检测
cin.get()
类似传统getchar 读取空白,且返回读取到的char,读到eof,返回eof
典型用例:while( (ch=cin.get()) != EOF ){}
cin.eof() cin.fail()
ifstream对象
用法基本等同cin 但必须包含fstream类,必须声明对象,和打开关闭对应的文件
成员函数
//常见范例 #include <fstream> using namespace std ; //例一 fstream file1 ; file1.open("example.txt") if(!file1.is_open()) { cout << "some failure info" exit(EXIT_FAILURE) ; }
Copy
C++
fstream.open("C Style Strings")
fstream.is_open() 成功打开则返回true
fstream.close()
fstream.good()fstream.fail() .bad() .eof()都为0时,其为1
💡
KEY:编写逻辑:—-操作—-检验问题—-处理差错