一.类型增强
1.1类型更严格
const类型的指针赋值给非const类型的指针。C可以编译通过,但是在C++编译不过去。
int main()
{
const int a = 100;
int b = a;
const int *pa = &a;
int *pb = pa;
return 0;
}
1.2.布尔类型(bool)
C语言的逻辑真假用0和非0来表示。而C++有了具体的类型。
int main()
{
bool flag = true;
if (flag != flase)
{
printfI("i know bool type now!\n");
}
printf("bool size = %d\n", sizeof(bool));
return 0;
}
1.3.真正的枚举
C语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而C++中枚举变量,只能用被枚举出来的元素初始化。
enum season {SPR, SUM, AUT, WIN};
int main()
{
enum season s = SPR;
//s = 0; //error
return 0;
}
编译error
F:\qt-test\const\main.cpp:9: 错误:invalid conversion from 'int' to 'season' [-fpermissive]
1.4.表达式的值可被赋值
C语言中表达式通常不能作为左值, 即不可被赋值,C++中某些表达式是可以被赋值的。
int main()
{
int a, b = 5;
(a = b) = 100;
cout << "a = " << a << " b = " << b << endl;
(a<b?a:b) = 200;
cout << "a = " << a << " b = " << b << endl;
return 0;
}
二.输入与输出(cin/cout)
第一一个真正意义上的C++程序, C++程序的后缀为cpp。假设程序名叫xxx,则应该写成xxx.cpp。
2.1.cin && cout
cin和cout是C++的标准输入流和输出流。他们在头文件iostream中定义。
流名 | 含义 | 隐含设备 | 流名 | 含义 | 隐含设备 |
cin | 标准输入 | 键盘 | cerr | 标准错误输出 | 屏幕 |
cout | 标准输出 | 屏幕 | clog | cerr的缓冲输出 | 屏幕 |
int main()
{
char name[30] = {0};
int age;
cout << "pls input name and age:" << endl;
cin >> name;
cin >> age;
//cin >> name >> age;
cout << "your name is :" << name << endl;
cout << "your age is:" << age << endl;
return 0;
}
//string name 安全性对比
//%d%c 的问题
2.2.格式化
C语言中printf拥有强大的格式化控制。C++亦可以实现,略复杂。
2.2.1.设置域宽及位数
对于实型,cout默认输出六位有效数据,setprecision(2)可以设置有效位数,setprecision(n) << setiosflags(ios::fixed)合用,可以设置小数点右边的位数。
#include <iostream>
#include <iomanip>
using namespace std;
int main()
{
printf("%c\n%d\n%f\n", 'a', 100, 120.00);
printf("%5c\n%5d\n%6.2f\n", 'a', 100, 120.00);
cout << setw(5) << 'a' << endl << setw(5) << 100 << endl << setprecision(2) << setiosflags(ios::fixed) << 120.00 << endl;
return 0;
}
2.2.2. 按进制输出
输出 十进制,十六进制,八进制。默认输出十进制的数据。
int i = 123;
cout << i << endl;
cout << dec << i << endl; //十进制
cout << hex << i << endl; //十六进制
cout << oct << i << endl; //八进制
cout << setbase(16) << i << endl; // 8为八进制 16为十六进制 其他值为十进制
2.2.3.设置填充符
还可以设置域宽的同时,设置左右对齐及填充字符。
int main()
{
cout<<setw(10)<<1234<<endl;
cout<<setw(10)<<setfill('0')<<1234<<endl;
cout<<setw(10)<<setfill('0')<<setiosflags(ios::left)<<1234<<endl;
cout<<setw(10)<<setfill('-')<<setiosflags(ios::right)<<1234<<endl;
return 0;
}
三.函数重载
3.1.引例
如下函数分别求出整理数据和浮点数据的绝对值:
int iabs(int a)
{
return a>0?a:-a;
}
double fabs*(double a)
{
return a>0?a:-a;
}
C++致力于简化编程,通过函数重名来达到简化编程的目的。
int abs(int a)
{
return a>0?a:-a;
}
double abs*(double a)
{
return a>0?a:-a;
}
3.2.重载规则与调用匹配(overload&match)
重载规则:
- 函数名相同
- 参数个数不同,参数的类型不同,参数的顺序不同,均可构成重载
- 返回值类型不同则不可构成重载
如下:
void func(int a); //ok
void func(char a); //ok
void func(char a,int b); //ok
void func(int a, char b); //ok
char func(int a); //与第一个函数有冲突
有的函数虽然有返回值类型,但不与参数表达式运算,而作一条单独的语句。
规则匹配:
- 严格匹配,找到则调用
- 通过隐式转换寻求一个匹配,找到则调用
#include <iostream>
using namespace std;
void print(double a){
cout<<a<<endl;
}v
oid print(int a){
cout<<a<<endl;
}i
nt main(){
print(1); // print(int)
print(1.1); // print(double)
print('a'); // print(int)
print(1.11f); // print(double)
return 0;
}
注:
C++允许,int 到 long和double,double 到 int和float隐式类型转换 。遇到这种情形,则会引起二义性。
解决方法,在调用时强转。
3.3.重载底层实现(name mangling)
C++利用name mangling*(倾轧)技术,来改名函数名,区分番薯不用的同名函数。
实现原理:用v-c-i-f-l-d表示void char int float long double及其引用。
void func(char a); // func_c(char a)
void func(char a, int b, double c);
//func_cid(char a, int b, double c)
3.4.extern "c"
name manling 发生在两个阶段, .cpp编译阶段,和.h的声明阶段。只有两个阶段同时进行,才能匹配调用。
mystring.h
extern "C" {
int myStrlen(char *str);
}
mystring.cpp
int myStrlen(char *str)
{
int len = 0;
while(*str++)
len++;
return len;
}
main.cpp
#include <iostream>
#include "mystring.h"
using namespace std;
int main()
{
char *p = "china";
int len;
len = myStrlen(p);
return 0;
}
C++完全兼容C语言,那就面领着,完全兼容C的类库。由.c文件的类库文件函数名,并没有发生name mangling行为,而我们在包含.c文件所对应的.h文件时,.h文件要发生name mangling行为,因而会发生链接的时候的错误。
C++为了避免上述错误的发生,重载了关键字extern。只需要,要避免name mangling的函数前, 加extern "C" 如多个, 则extern "C"{}
我们看一个系统是怎么处理的:
string.h
extern "C" {
char * __cdecl _strset(char *_Str,int _Val) __MINGW_ATTRIB_DEPRECATED_S
EC_WARN;
char * __cdecl _strset_l(char *_Str,int _Val,_locale_t _Locale) __MINGW
_ATTRIB_DEPRECATED_SEC_WARN;
char * __cdecl strcpy(char * __restrict__ _Dest,const char * __restrict
__ _Source);
char * __cdecl strcat(char * __restrict__ _Dest,const char * __restrict
__ _Source);
int __cdecl strcmp(const char *_Str1,const char *_Str2);
size_t __cdecl strlen(const char *_Str);
size_t __cdecl strnlen(const char *_Str,size_t _MaxCount);
void *__cdecl memmove(void *_Dst,const void *_Src,size_t _Size) __MINGW
_ATTRIB_DEPRECATED_SEC_WARN;
}