类型增强
1、类型更加严格
不初始化,无法通过编译;C不初始化,则随机赋值
#include <iostream>
#include <stdlib.h>
int main()
{
const int a = 100; //真正的const,无法修改
// int *p = &a; 报错
const int *p = &a;
char *p = (char)malloc(100); //malloc 得到的是void *
return 0;
}
C++不喜欢指针和强制类型转换
2、增加bool类型(其实是增加了枚举)
C语言中表示真假,用0和非0
string s;
bool b = true / false;
enum BOOL{ FALSE, TRUE};
BOOL a = FALSE;
3、枚举等价关系
#define Spr 0
#define Sum 1 宏
enum
{
Spr=1, Sum, ...
};
C++中尽量不用宏,能用枚举代替就用枚举
输入与输出
C语义中,表达式不能赋值
#include <stdio.h>
int main()
{
int a, b = 5;
a = b = 100;
(a = b) = 100; //100是对a的赋值 C语言中报错
printf("a = %d b = %d", a, b);
return 0;
};
C++表达式可以赋值
#include <iostream>
int main()
{
int a, b = 10;
a = b = 100;
printf("a = %d b= %d\n", a, b);
(a != b ? a : b) = 1000; //输出a=100, b=1000
return 0;
}
输入与输出
# include <iostream>
using namespace std;
//cin cout 类对象,scanf sprinf 相同的功能,函数
int main()
{
//char name[30];
//scanf("%s", name); //不安全 超过30个字符会崩溃
//gets(name); //不关心溢出问题,不安全
// 键盘中的输入流入到name中
//cin>>name; // >> 流输入运算符(重载 也代表右移) 超过30个字符会崩溃
string name; //安全 从语言层规定
cin>>name;
cout<<"name="<<name<<endl;
//"name=" name endl 均流入到cout中,等价于一个一个赋值
cout<<"name="<<name<<endl;
printf("name = %s\n", name);
return 0;
}
# include <iostream>
# include <iomanip>
using namespace std;
int main()
{
//C++ 不受空格控制
int a = 12345; int b = 1234.567;
cin>>a>>b; // cin>>a cin>>b
cout<<a<<b<<endl; //endl \n
cout<<setw(8)<<a<<endl; //引入头文件 iomanip
cout<<setiosflags(ios::left)<<setw(8)<<a<<endl; //左对齐
cout<<b<<endl; //输出两位小数点
return 0;
}
函数重载
# include <iostream>
//函数重载(静多态)
// 函数名相同,参数列表不同 类型 个数 顺序
int abs(int data)
{
return data>0?data:-data;
}
float abs(float data)
{
return data>0?data:-data;
}
int main()
{
float ret = abs(-5.5f); //ambiguous 二义性
cout<<ret<<endl;
int ret2 = abs(5);
cout<<ret2<<endl;
return 0;
}
匹配原则:
1、严格匹配,找到则调用;2、通过隐式转换寻求一个匹配,找到则调用.
倾轧技术
C++ 完全兼容 C (语法、标准lib库 不会参加倾轧)string.h stdlib.h stdio.h
C++函数重载底层实现原理是C++利用name mangling(倾轧)技术,来改名函数名,区分参数不同的同名函数
C++命名倾轧的函数是无法被C语言调用的。C++的函数必须是没有倾轧的才能调用。 使用声明extern "C"的函数会禁止命名倾轧,这样C++的函数就可以被C语言调用。
str.cpp
#include <iostream>
int mystrlen(char *p)
{
int len = 0;
while(*p)
{
len++;
p++;
}
return 0;
}
str.h 头文件
#ifndef STR_H
#define STR_H
int mystrlen(char *p);
// extern "C" int mystrlen(char *p);
#endif //STR_H
main.cpp
#include <iostream>
#include "str.h"
using namespace std;
int main()
{
int n = mystrlen("china");
cout<<n<<endl;
return 0;
}
操作符重载Operator Overload
C++认为一切操作符都是函数。函数是可以重载的(并不是所有的运算符都可以重载)。
#include <iostream>
using namespace std;
struct Complex //结构体 复数
{
float real;
float image;
};
Complex operator+(Complex a, Complex b)
{
Complex c;
c.real = a.real + b.real;
c.image = a.image + b.image;
return c;
}
int main()
{
int a = 1; int b = 2;
int c = a + b;
cout << "c: " << c << endl;
Complex aa = {1, 2}, bb = {2, 3};
Complex cc = aa + bb; // 报错--增加了operator+,可执行
Complex cc = operator+(aa, bb); //可执行
cout<<"c = "<<"("<<c.real<<","<<c.image<<")"<<endl;
return 0;
}
默认参数default parameters
#include <iostream>
#include <time.h>
using namespace std;
void weatherCast(string w = "pm2.5")
{
time_t t = time(0); //170,0,0,0
char tmp[64];
strftime(tmp, sizeof(tmp), "%Y/%m/%d %X %A ", localtime(&t) );
cout<<tmp<<"today is weather "<<w<<endl;
}
//从右向左默认,中间不能跳跃
//实参的个数+默认参数的个数 >= 形参的个数
int volume(int l, int w, int h=5)
{
return l*w*h;
}
int main()
{
weatherCast();
weatherCast();
weatherCast("sunshine");
cout<<volume(1, 2)<<endl;
cout<<volume(1, 2, 10)<<endl;
return 0;
}
include <iostream>
using namespace std;
//void print(int a)
//{
// printf("void print(int a)\n");
//}
void print(int a, int b = 10)
{
print("void print(int a, int b = 10)\n");
}
int main()
{
print(1, 20); // 1个参数或2个参数的形式,重载,默认参数都可以实现,但是不可同时存在
return 0;
}
引用Reference
- 引用是一种声明关系,声明的时候必须要初始化。引用不开辟空间,不分配内存。
- 此种声明关系,一经声明,不可变更。
- 可以对引用再次引用。多次引用的结果是多个引用指向同一个地址。
- 引用必须与原类型保持一致。
#include <iostream>
using namespace std;
int main()
{
int a = 500; //变量名实质是一段内存空间的别名
//*(int *)0xb0002345 = 500;
int& ra = a; // 声明 ra 是a的引用(别名)
printf("sizeof(a) = %d, sizeof(ra) = %d\n", sizeof(a), sizeof(ra));
printf("&a = %p &ra = %p", &a, &ra);
a = 100;
printf("a = %d ra = %d\n", a, ra);
ra = 2000;
printf("a = %d ra = %d\n", a, ra);
int b = 200;
ra = b; // 赋值
int &ra = b; //声明
int& rr = ra; //再次引用
printf("a = %d ra = %d rr = %d\n", a, ra, rr);
return 0;
}
#include <iostream>
using namespace std;
void swap(int *pa, int *pb)
{
*pa ^= *pb;
*pb ^= *pa;
*pa ^= *pb;
}
void swap(int &ra, int &rb)
{
ra ^= rb;
rb ^= ra;
ra ^= rb;
}
//平级内解决问题,然后不开辟多余的空间
//引用的目的是对指针的再次包装。指针是有引用的,但不应该有引用的指针。
void swap(char* &p, char* &q)
{
char *t = q;
q = p;
p = t;
}
int main()
{
int a = 5; int b = 3;
swap(a, b);
cout<<"a= "<<a<<" b= "<<b<<endl;
char *p = "china"; // 定义指针的引用 char* & rp = p
char *q = "america";
cout<<"p = "<<p<<" q = "<<q<<endl;
swap(p, q);
cout<<"p = "<<p<<" q = "<<q<<endl;
return 0;
}
避免C语言指针的缺陷,不能定义引用的引用,但可以定义指针的指针(二级指针)
#include <iostream>
using namespace std;
int main()
{
int a;
int * p = &a; //定义指针
int **pp = &p; //定义指针的指针(二级指针)
int b;
int &rb = b; //定义引用
int * &rp = p; //定义指针的引用
//报错,不能定义引用的引用
int & & rrp = rp; ❌
//不能定义引用的指针,引用就是对指针的包装,不希望再打开
int& * p = &rb; ❌
int x, y, z;
int * p[] = {&x, &y, &z} //可以建立指针的数组
int & rp [] = {x, y, z}; ❌ //不可以定义引用数组 rp int& *
return 0;
}
数组引用
int arr[]= {1, 2, 3, 4, 5};
int(&rarr)[5] = arr;
常引用
- const对象的引用必须是const的,将普通引用绑定到const对象是不合法的
- const引用可使用相关类型的对象(常量、非同类型的变量或表达式)初始化
const int a = 100;
const int &ra = a;
int a;
const double & ra = a + 5;
先定义了 double tmp = a 然后定义 const double rb = tmp
use const whatever possible原因:文章来源:https://www.toymoban.com/news/detail-670548.html
- 使用const可以避免无意修改数据的编程错误
- 使用const可以处理const和非const实参,否则只能接受非const数据
- 使用const引用,可使函数能够正确的生成并使用临时变量(如果实参与引用参数不匹配,就会生成临时变量)
文章来源地址https://www.toymoban.com/news/detail-670548.html
到了这里,关于C++(3)C++对C的扩展Extension的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!