1.C++的部分基础知识简单小结之C++对C的扩充

输入与输出

在C++中我们用输入流函数cin和输出流函数cout进行标准输入/输出操作,同时用到的运算符有流插入运算符<<流提取运算符>>,使用时需要包含输入输出流的头文件<iostream>,具体使用如下例:

#include<iostream>
#include<string>
using namespace std;

int main() {
    string str;
    cin>>str;
    cout<<"Hello World!"<<endl;
    return 0;
}

在C的标准输入里,我们可以指定数制进行输出,在C++中,我们也可以对整数指定数制输出,常用数制如下表:

数制关键字
oct
dec
十六hex

注:不能想当然认为bin是二进制的关键字,C++中没有bin关键字

以上的数制使用setbase(int)函数一样能实现,该函数的作用见下表:

参数值作用
8以8进制输出
10以10进制输出
16以16进制输出
其他iosflags重置为默认

所谓iosflags,即输入输出流标记,该标记存在于ios_base::basefield中,其有效值只有8,10,16,对应oct,dec,hex关键字,因此bin是无效关键字,其中10为默认的iosflags,重置即将从该位置往后的输出均使用10进制输出

注:

cout中指定数制以后,直到输出结束或遇到下一次重新指定才改变,否则将一直以指定数制进行输出

使用setbase(int)需要导入头文件<iomanip>

#include<iostream>
#include<iomanip>
using namespace std;

int main() {
    int a = 10;
    cout<<oct<<a<<" "<<dec<<a<<" "<<hex<<a<<" "<<setbase(32)<<a<<" "<<setbase(16)<<a<<" "<<endl;
    return 0;
}

说到<iomanip>,我们再来介绍另一个包含于其中的格式控制函数:setw(int)

setw(int)的作用很简单,就是设置输出变量的宽度,不足则自动补齐,超过宽度则原样输出,补齐的方式和设置的对齐方式有关,C++默认左对齐,可以使用std::left,std::right设置对齐方式,样例如下:

#include<iostream>
#include<iomanip>
using namespace std;

int main() {
    cout<<setw(4)<<1<<setw(4)<<1<<endl;
    cout<<std::left<<setw(4)<<1<<setw(4)<<1<<endl;
    cout<<std::right<<setw(4)<<1<<setw(4)<<1<<endl;
    return 0;
}

注:

cout中指定宽度以后,直到输出结束或遇到下一次重新指定才改变,否则将一直以指定宽度进行输出

<iostream>还含有其它输入/输出方式,cincout也带有其他方法,具体内容稍后介绍.

常变量

C使用#define预编译命令定义常量,C++使用const定义常变量,他们的区别如下:

方式存储单元数据类型指针指向
#define简单替换,不可改变不能被指向
const一次赋值,不可改变可以被指向

可见C++中const定义的常变量,既有常量的特点,又有变量的特点,简单例子如下:

#include<iostream>
#include<cmath>
using namespace std;

int main() {
    double r = 10;
    const double PI = 3.14;		//和#define一样,常变量声明时必须有初值;
    cout<<PI*pow(r,2)<<endl;
    return 0;
}

函数重载与模板函数

对于功能相同,参数类型不同/参数个数不同的函数,我们可以使用重载(overload),即使用同名函数完成不同的功能,重载函数的条件为:

两个函数的参数类型参数个数二者至少有一个不同,下面是一个简单例子:

#include<iostream>
using namespace std;

int Max(int a,int b) {
    return a > b ? a : b;
}

double Max(double a,double b) {
    return a > b ? a : b;
}

int Max(int a,int b,int c) {
    if(a < b)   a = b;
    if(a < c)   a = c;
    return a;
}

int main() {
    int a = 3,b = 5,c = 17;
    double d = 8.8,e = 10.5;
    cout<<Max(a,b)<<" "<<Max(a,b,c)<<" "<<Max(d,e)<<endl;
    return 0;
}

从上面的例子我们可以看出double Max(double,double)int Max(int,int),仅仅是参数类型不一样,其余完全一样,为了提高代码的可重用性,我们可以将其写成函数模板(的形式,函数模板声明如下:

template<typename T>
T Max(T,T);

template<class T>
T Max(T,T,T);

即,将多个仅有参数类型不同的,实现完全一致的函数的参数类型用一个抽象类型typename T来表示,实现的时候用T来作为类型实现函数体,实际调用的时候,采用简单替换的方式,将实际类型代入T的位置,即可完成对不同类型函数的实现,这样的函数叫做函数模板,比如:

#include<iostream>
using namespace std;

template<typename T>
T Max(T a,T b) {
    return a > b ? a : b;
}

int main() {
    int a = 3,b = 5;
    double c = 19.1,d = 3.3;
    cout<<Max(a,b)<<" "<<Max(c,d)<<endl;
    return 0;
}

注:

返回值类型不同不可作为函数重载的条件

使用函数模板必须声明为模板(使用template关键字),classtypename均可声明抽象类型

带有默认参数的函数

在C++中,允许函数参数带有默认值,当该位置不传实参进来时,函数使用默认参数,如:

int func(int a,int b = 0) {
    return a*b;
}

func(5);	//相当于func(5,0);
func(5,5);

注:

若有多个参数含有默认值,将这些参数声明于函数的最右方,如:

double fun(int a = 0,int b,int c,double d = 5.5)	//语法错误;
double fun(int b,int c,int a = 0,double d = 5.5)	//正确;

带默认值的参数不能进行重载,否则会引起程序的二义性

变量的引用

C++中引入引用类型,它和指针的区别大概是:引用的变量和原变量是同一变量,指针指向变量的存储地址,但指针不能代替原变量,虽然它可以通过修改指针指向的值来修改原变量内容,但若原变量是一个指针型变量,则用指针指向原变量将无法修改原变量的指向(只能修改当前指针的指向)

引用的最大用途就是作为参数传入函数中,达到修改实参值/修改实参指向的目的,以二叉树的建立为例:

struct BTT {
    char data;
    struct BTT *lc,*rc;
};

void initBTT(BTT *&T) {
    char ch;
    cin>>ch;
    if(ch == '@') {
        T = nullptr;
        return;
    }
    T = new BTT;
    T->data = ch;
    initBTT(T->lc);
    initBTT(T->rc);
}

上述代码中,若声明写成:

void initBTT(BTT *T)

则新建的二叉树在建立完成后,主函数传入的树根T将会无法指向这棵二叉树,导致对其操作时发生错误

而交换数据的函数用引用实现再好不过了:

void Swap(int &a,int &b) {
	a ^= b ^= a;
}

忘了说引用的基本定义了:

int &a = b;		//声明a是b的引用,即a是b的别名,a和b实际上是同一变量;

内联函数

对于码量短小且执行频繁的简单函数,C++支持使用内联函数,相当于预编译命令,它可以给编译器一个建议,即在编译之前将内联函数函数体嵌入到其调用的位置上去,可以减少编译时间,进而加快程序执行速度,内联的关键字是inline

注:inline只是一个建议,编译器并不总是使用内联处理,为了让inline起作用,建议将不含循环控制的(for、switch、while等)、代码长度不超过10行且使用频率较高的函数声明为inline,举例如下:

template<typename T>
inline T Max(T a,T b,T c) {
    if(a < b)	a = b;
    if(a < c)	a = c;
    return a;
}

作用域运算符::

C语言中,我们可以通过成员运算符.或是->(指针)访问结构体的成员变量,这些运算符在C++中依旧有效,除此之外,C++中还引入了作用域运算符::,该运算符在C++的面向对象中使用较多,运算符的意义是作用域的某成员(field::member),注意,域运算符::不能用来指定某个具体的结构的成员,因为作用域是抽象的,不能和具体化的对象混为一谈,下面写一些正确/错误的例子:

#include<iostream>
using namespace std;

int a = 5;	//全局变量a;

struct T {
    static string str;
    int num;
};

int main() {
    T t;
    int a = 10;
    cout<<a<<endl;
    cout<<::a<<endl;	//使用全局变量a;
    t::str;		//错误,t是T类型的具体对象;
    T::str;		//正确,T是抽象的类型;
    return 0;
}

string类型

C++中字符串类型不再是使用char型数组,而是有专门的string类型,使用时导入头文件<string>

string类型的常用方法和迭代器如下表:

函数功能
empty()判空
size()获取string长度
length()同上
max_size()返回当前环境下string能分配的最大空间
resize(int n,char ch)给string重新分配长度,多补字符ch少截取原则
resize(int n)给string重新分配长度,多补字符’ '少截取原则
clear()清空string
front()指向第一个字符
back()指向最后一个字符
pop_back()删除最后一个字符
push_back(char ch)在最后插入一个字符ch
substr(int st,int end)截取从st到end-1长度的子串
assign()整体编排string,有多种重载形式,不能一一举例

对于string类型,需知道它是一个类型,其数据成员是私有的,因此虽然可以通过[]运算符访问其单个字符,但无法改变其值可以使用迭代器(常量迭代器除外)对其单个字符进行修改,以下列出了所有的迭代器:

迭代器说明
begin()起始迭代器
end()结束迭代器
rbegin()逆置起始迭代器
rend()逆置结束迭代器
cbegin()常量起始迭代器
cend()常量结束迭代器
rcbegin()逆置常量起始迭代器
rcend()逆置常量结束迭代器

同样可以使用部分算数运算符和逻辑运算符对string进行操作:

运算符功能
+起连接作用
+=同上
=赋值
==判等
!=判不等
<按strcmp()的规则比较,返回bool值
<=按strcmp()的规则比较,返回bool值
>按strcmp()的规则比较,返回bool值
>=按strcmp()的规则比较,返回bool值

关于string的方法,无法全部列出,有兴趣可以查阅工具书,下面写一个简单的标程:

#include<iostream>
#include<string>
using namespace std;

int main() {
    string str1 = "I love C",str2;
    cout<<str1<<endl;
    str1.resize(str1.size()+2,'+'); //将str1的长度+2,用'+'填充额外长度;
    cout<<str1<<endl;
    cout<<str1.substr(0,8)<<endl;   //截取str1从0~7的子串;
    for(string::iterator it = str1.begin();it < str1.end()-2;it++)  //迭代器修改单个元素的值;
        *it = '0';
    cout<<str1<<endl;
    for(string::reverse_iterator it = str1.rbegin();it < str1.rend()-2;it++)    //反向迭代器修改单个元素的值;
        *it = '9';
    cout<<str1<<endl;
    str1.assign(str1.rbegin(),str1.rend()); //逆置str1;
    cout<<str1<<" "<<str1.size()<<endl;
    str2.assign(str1.begin(),str1.end()-2); //将str1的0~size-2个字符给str2;
    cout<<str2<<" "<<str2.length()<<endl;
    cout<<str1.back()<<endl;    //输出str1的最后一个字符;
    cout<<str2.front()<<endl;   //输出str2的第一个字符;
    for(int i = 0; i < 3; i++) {
        str1.push_back(cin.get());  //输入三个字符,插入到str1最后;
        str2.pop_back();    //删除str2最后三个字符;
    }
    cout<<str1<<" "<<str2<<endl;
    if(str1 > str2) cout<<"Yes!"<<endl; //比较;
    str2 = str1;    //赋值;
    while(!str1.empty()) {  //清空str1;
        str1.pop_back();
    }
    str2.clear();   //清空str2;
    if(str1.empty() && str2.empty())
        cout<<"Cleared!"<<endl;
    return 0;
}

new和delete运算符

关于newdelete,只需知道以下几点:

1.new关键字对应C中的malloc(sizeof type),delete相当于free(pointer),作用分别是为某个类型分配空间,撤销空间,和malloc()不同的是,new返回该类型的指针,malloc()返回没有类型的指针

2.使用new动态建立的空间,必须使用delete删除,它们总是成对出现(类比malloc()free())

3.关于newdelete的配合使用,大概是以下这样:

int *a = new int;	//申请单个空间;
delete a;	//单个释放;
a = nullptr;

int *b = new int[10];	//申请连续空间;
delete[] b;	//连续释放;
b = nullptr;

4.无论是deletefree(),释放空间均没有将指针置空,请自动置空(nullptr)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值