一、面向过程与面向对象
C语言是面向过程的语言,更注重程序的逻辑性,就是将一个程序分解成一个个小模块完成,然后将所有模块有序调动起来,所以它可以更快更直接的形成一个完整的程序。
但是对于大型程序而言,C语言并不利于程序的复用性、扩展性和可维护性。
C++是面向对象的语言,更方便于复用和扩展,更注重程序的整体
优缺点总结:
面向过程的优点:因为更快更直接的完成某一种功能,所以性能更好,效率更高,比如单片机、嵌入式、linux等,比较追求性能因素的方向
面向过程的缺点:不方便维护、复用、扩展
面向对象优点:方便于维护、复用和扩展
面向对象缺点:调用时需要实例化,比较消耗资源,导致性能低
C++兼容包含了C语言,同时还增加了函数重载、类、继承、多态、STL库,并且支持泛型编程(模板函数、模板类)
一些常用的概念
封装:就是将零散的东西放到一个集合里
复用:针对某一“类”功能去开发,而不是针对某一“个”功能去开发
扩展:增加新功能,而不影响原来的功能
//C++支持函数重载
int add(int a,int b)
{
return a+b;
}
double add(double a,double b)
{
return a+b;
}
int main()
{
add(10,20);
add(10.1,10.2)
}
//C++支持函数模板
template<tempname T>
T add(T a,T b)
{
return a+b;
}
int main()
{
add(10,20);
add('a','b');
}
二、输入和输出
#include<iostream>//C++中标准的输入输出文件
using namespace std;//打开标准命名空间
int main()
{
int a=10;
char b='b';
printf("%d %c\n",a,b);
cout<<a<<" "<<b<<endl;
//cout 是ostream的变量
//<<:输出操作符,是符号被重载的函数
//endl:换行,本质也是一种函数
scanf("%d %c",&a,&b);
cin>>a>>b;
//cin 是istream的变量
//>>:输入操作符,是符号被重载的函数
}
三、命名空间
//namespace:命名空间,区分同一作用域下相同的变量名
//命名空间有两种使用方法:1.显示的指定命名空间 命名空间::变量名 2.打开命名空间 using namespace AA 注意:打开多个命名空间可能会产生冲突
namespace AA
{
int a;
}
namespace BB
{
int a;
}
//int a;
int main()
{
int a=10;
cout<< a <<endl;//局部优先级变量高于全局变量
//:: 作用域运行符,符号前放作用域名,符号后放变量名,符号前没有作用域名默认为全局变量
//cout<<::a<<endl;
cout<<AA::a<<endl;
cout<<BB::A<<endl;
}
四、动态申请空间
//在C中动态申请空间,堆区申请
int *p1=(int*)malloc(sizeof(int));
*p1=10;//赋值
cout<<*p1<<endl;
free(p1);
p1=NULL
//在C++中动态申请空间,在堆区申请
//new是关键字,后面放申请的类型,返回的是对应类型的地址
int *p2=new int;
*p2=20;
cout<<*p2<<endl;
delete p2;
p2=NULL;
int *p3=new int(30);
*p3=30;
cout<<*p3<<endl;
delete p3;
p2=NULL;
int *p4=new int[5];
for(int i=0;i<5;i++)
{
cin>>*p4[i];
}
for(int i=0;i<5;i++)
{
cout<<*p4[i]<<endl;
}
delete[]p4;
p4=NULL;
int *p5=new int[5]();//申请空间且初始化为类型的初始值
for(int i=0;i<5;i++)
{
cout<<*p5[i]<<endl;
}
delete[]p5;
p5=NULL;
int *p6=new int[5]{1,2,3,4,5};
for(int i=0;i<5;i++)
{
cout<<*p6[i]<<endl;
}
delete[]p6;
p6=NULL;
malloc 和new 的区别:
1.malloc需要提供申请空间的大小,new只需要提供申请空间的类型,会根据申请的类型自动计算大小;
malloc的返回值是是泛型指针void*,需要强转,new返回值是所申请的类型
2. malloc是函数,需要依赖头文件,new是关键字,依赖于编译器
3.malloc申请后不能直接初始化,new可以。
4.最重要的:申请结构体和类对象可以直接调用构造函数,delete调用自动调用析构函数
//new一个整型指针
int **p1=new int*;
delete p1;
p1=NULL;
//new一个指针数组
int **p2=new int*[3]
delete []p2;
p2=NULL;
//new一个数组指针
int (**p3)=new (int (*) [3])
delete p3;
p3=NULL;
//new一个二维整型数组
int (*p4)[3]=new int[2][3];
delete p4;
p4=NULL;
五、bool和BOOL
bool,true,false是C++中的关键字,定义变量所需空间大小为1个字节
BOOL是int的别名(typedef),TRUE和FALSE分别是1和0的宏,定义变量所需空间大小为4 个字节
六、字符串
在C语言中使用字符串方法
char *p=(char*)"12345";
p=(char*)"54321"; //修改的不是原字符串的内容而是指针指向的地址
//正确的修改
char arr[5]="1234";
strcpy_s(arr,5,"4321");
//比较两个字符串时
char arr2[5]="4321";
if(arr==arr2) //输出结果为不相等,因为比较的是两个数组的地址
{
cout<<"相等"<<endl;
}
else
{
cout<<"不相等"<<endl
}
由上述两个例子可以看出来,在修改字符串的值的时候,不能直接用=,因为修改的不是内存空间里的值,而是指针指向的空间,需要使用函数strcpy_s();比较的时候不能使用==,因为比较的是地址而不是空间里的值,C语言中使用字符串还是不是很方便
#include<string>
using namespace std;
int main()
{
string str="1234';
str[1]='9';//通过下标修改
str="4321";//直接赋值
string str2="1234";
if(str!=str2)//通过!=和==直接对比两个字符串
{
cout<<"不相等"<<endl;
}
//可以像数组一样用for循环去遍历
for(int i=0;i<str.size();i++) //size()是C++提供的计算字符串大小的方法
{
cout<<str[i]<<" ";
}
cout<<endl;
cout<<str.length()<<endl;
}
//string的拼接可以直接使用+ +=
string str1="123";
string str2=str1+"456";
str1+="456";
//string的截取 substr(开始截取的下标,截取的长度)
string str3=str1.substr(2,4);
string str4=str1.substr(2,40);//截取长度超过数组长度,默认截取到末尾
string str5=str1.substr(20,4);//截取下标超过数组长度,不合法,相当于数组越界
void fun(const char* c);
string str="abc";
fun(str);//报错
//c_str()可将string转为c_str
fun(str.c_str);
七、增强for循环
//for(相同类型的变量(用于接应元素):操作的数组)
int arr[5]={1,2,3,4,5};
for(int a:arr)
{
cout<<a<<" ";
}//缺点无法得知相应下标
int *p=new int arr2[3]{1,2,3};
for(int a:arr2)
{
cout<<a<<" ";
}//非法操作,只知道地址,无法知道数组长度,遍历到哪
string str("12345");
for(char a:str)
{
cout<<a<<" ";
}
增强for循环的遍历可以用于数组、string和支持begin、end的容器
八、C++函数重载
函数重载:对于多个函数,在同一作用域下,函数名相同,参数个数、类型、顺序不同,对返回值没有要求
函数重载方便对一类函数进行命名,减少程序员在命名上花的心思,编译器可以自动匹配
int add(int a,int b);
double add(double a,double b);
int add(int a,int b,int c);
但是要注意,以下两个函数属于函数重定义而不是函数重载
void fun(char *p);
void fun(char p[]);
在C++中,还允许函数的参数指定默认值,规则是,从右往左依次指定而不允许间断。
void fun1(int a,int b,int c=30);
void fun2(int a,int b=20,int c=30);
void fun3(int a=10,int b=20,int c=30)
//错误示范
void fun4(int a,int b=20,int c)
注意:如果函数的声明和定义分开写,一般将默认值写在函数的声明里
九、nullptr和NULL
都是为了防止野指针的存在
//NULL是#define NULL 0
void fun(int a);
void fun(int *P);
void(NULL);
//匹配第一个函数
NULL在使用时会出现与整型混用的情况
//正确使用需要强转
fun((int*)NULL)
nullptr是C++提供的关键字,有特定的含义:空指针
fun(nullptr);//可以正确匹配指针参数
//特殊情况仍需强转:当两不同类型的指针作为参数函数重载时
void fun(int *p);
void fun(char *p);
fun((int*)nullptr);
十、引用
1.引用就是对已有的变量(已经存在的空间)起一个别名
2.引用不会再额外申请空间
3.引用一旦声明就必须初始化
4.引用一旦初始化就不可修改
int a=10;
int &b=a;//必须初始化
int c=20;
b=c//不是修改,而是赋值
对于值传递、地址传递、引用传递:
对于修改实参的情况可以使用地址传递和引用传递
空间:
值传递要将实参空间拷贝一份,空间大小不可控
地址传递开辟一个指针大小的空间,由指针类型决定,大小
引用传递不开辟空间
值传递对于复合类型,类、结构体可能出现浅拷贝问题
注意:引用可以const,但是会出现警告