1.C++与C语言的不同
C++是强类型语言,C语言是弱类型语言 |
void main() { //C++注重类型,强类型,严格检查类型 int *p1=NULL; double *p2=NULL; p1 = p2; // C++中error C2440: “=”: 无法从“double *”转换为“int *” // C语言中warning C4133: “=”: 从“double *”到“int *”的类型不兼容 } |
C语言与C++输出宽字符(中文) |
C语言: #include <locale.h> wchar_t *str = L"中国"; setlocale(LC_ALL, "chs"); wprintf(L"%ls", str); C++语言: wchar_t *str = L"中国"; wcout.imbue(std::locale("chs")); wcout << str; |
C++语言初始化变量方法(括号) |
int a(5); double a(3.5); char *str("china"); wchar_t *str(L"china"); |
C语言缺陷(引进命名空间的原因) |
C语言不允许在相同的工程中的不同文件中定义相同的函数名,全局变量。 C语言一旦定义全局变量,然后定义了和全局变量同名的局部变量,那么将不能引用全局变量了,C++可以用::变量名引用。 |
命名空间 |
|
外部变量的不同 |
C语言使用static在一个文件中定义一个变量,在另一个文件中extern该变量,不会报错,C++报错。 extern.cpp/c static int a = 10; main.cpp/c extern int a; // C/C++语言不报错当,当有打印a的值的语句的时候编译报错。LNK2001: 无法解析的外部符号 "int a" (?a@@3HA) extern int a = 5; // C++语言,C语言都不报错,并且都能打印。 注:静态变量的作用于只是该文件内,所以两个a并不是同一个a,可以通过定义一个外部指针变量打印。 |
全局变量的重定义问题 |
int g_var; int g_var = 1; C语言没问题,C++语言报错,说明C语言不初始化值就相当于只是声明了变量,如果第一条初始化一个值,那么照样报重定义。 |
C++新增的bool类型 |
占一个字节,0与1。 |
三目运算符 |
(a<b ? a : b) = 30; //C++中是没问题的,C语言报错 可以通过以下方法实现类似C++的功能。 *(a<b ? &a: &b) = 30; 当有常量的时候,C++将也失效。如:(a<b ? 1: b) = 30; C语言中的三目运算符返回的是变量值,不能作为左值使用 C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方 |
register区别 |
C语言中因为register变量可能不存放在内存中,所以不能用“&”来获取register变量的地址。 C++中一旦用”&“取地址,相当于普通变量,存到内存。 |
2.auto自动变量
auto基础 |
C++ 98标准/C++03标准 同C语言的意思完全一样:auto被解释为一个自动存储变量的关键字,也就是申明一块临时的变量内存。auto的出现意味着,当前变量的作用域为当前函数或代码段的局部变量,意味着当前变量会在内存栈上进行分配。 平时的double a=10.5;其实就相当于auto double a = 10.5;作用域在整个函数体中。 测试下边的例子,每次都是分配四个字节的内存。 C++ 11标准 在C++11标准的语法中,auto被定义为自动推断变量的类型 auto num = 10.5; //double auto numA = 10.0/3; //double auto numB = 10.5f; //float auto numC = 10.0; //double 只打印出10 C++11中auto double num = 10.5这样定义是会报错的。 |
auto可以用来遍历一维数组 |
for (auto data : num) // 泛型C++语法,循环一维数组,常量 { std::cout << data<<std::endl; } |
3.函数重载
函数重载成立的条件 |
|
得到函数地址 |
因为函数名字都一样所以不能通过函数名得到地址,可以通过函数指针指向具体的函数,得到地址。比如: void(*pgo1)(int a)=go; void(*pgo2)(double a)=go; void(*pgo3)(double a, int b)=go; void(*pgo4)(int a, double b)=go; printf("%p\n",pgo1); printf("%p\n", pgo2); printf("%p\n", pgo3); printf("%p\n", pgo4); |
4.函数的默认参数
函数默认参数规则 |
void print(int c,int a = 1, int d=2, int b = 3) { std::cout << a<<b<<c << std::endl; } void(*pt1)(int c, int a , int d , int b ) = print; |
5.引用
左值与右值 |
左值:放在赋值号左边可以被赋值的值,必须在内存中有实体。 右值:在赋值号右边取出给左值赋值的值,右值可以在内存也可在寄存器。 |
左值引用与右值引用 |
/* 对指针的引用 */ int num1 = 20; int num2 = 30; int *p = &num1; int * &rn1 = p; // p的别名 可以通过*rn1去改变num1的值 cout << p << endl; rn1 = &num2; cout << p << endl; int * &&rn2 = &num1; // &代表引用左值,&&代表引用右值,&num1的值在寄存器中 int *q = rn2; // 用于对象拷贝 |
函数返回值的引用 |
// 返回值的引用 int &geta() { int a = 30; int &ra = a; return ra; } |
函数返回指针的引用 |
// 返回对指针的引用 int * & getra() { /* 注意这个p是个变量,在栈上分配的内存空间用来存放堆上分配内存空间的首地址 */ int *p = new int; *p = 22; int *&rp = p; return rp; } |
通过上面两个函数,我们知道如果我们分别通过定义一个变量的引用,一个指针的引用去接收,只能第一次打印成功,一旦那块内存空间被重新使用那么将失效,我们可以理解引用只是一个别名的机制。我们应该顶一个一个变量以及一个指针变量去接收。 int ra = geta(); int *rpa = getra(); 而不是 int &ra = geta(); int *&rpa = getra(); |
6.const
C语言中的const |
const int a = 10; int arr[a]; 这是不允许的,因为C语言中的const是个假的。 再如可以通过 int *p=&a; *p=20; 修改a的值。 |
C++中的const |
C++中像上面那样修改a的值是改不掉的,并且int *p=&a;还要强制转换。 对于const_cast<int*>的转换,也不能去掉本身就是const的常量,但是本身是变量的被赋值给一个常量,可以去掉那个常量的属性。 C++中的const会使用一张常量表。 |
7.new/delete
delete说明 |
delete之后指针变量的值将改变。 |
给二维数组分配内存空间 |
int *p = new int[20]; int (*q)[4] = (int(*)[4])p; |
new与delete的重载 |
#include <iostream> #include <cstdlib> class Teacher { public: static int cnt; Teacher() { printf("一个teacher被构造\n"); } ~Teacher() { printf("一个teacher被析构\n"); } static void * operator new(size_t size){ printf("对象被创建.\n"); Teacher *teacher = ::new Teacher; // 全局的new默认就是去调用构造函数 cnt += 1; return teacher; } static void operator delete(void *teacher) { printf("对象被销毁.\n"); cnt -= 1; ::delete teacher; } }; int Teacher::cnt = 0; int main(void) { Teacher *t1 = new Teacher; Teacher *t2 = new Teacher; Teacher *t3 = new Teacher; delete t1; std::cout << Teacher::cnt << std::endl; system("pause"); return 0; } |