最近需要用C++做一些跨平台的组件,我自己本身对C++的语法不是特别熟练,也算是边写边学。 记录了一些平时开发过程中用到的语法笔记。
1.C++支持函数重载,C不支持。底层用了namemangling技术,通过编译器把函数名字改掉,每个方法名不一样。不同编译器有不同的生成规则。
2.extern “C”:
-
被extern “C” 修饰的代码会按照C语言的方式去编译。
1 2 3 4 5
extern "C" { void fun(){ count << "func()" << endl; } }
-
如果函数同时有声明和实现,要让函数声明被extern “C” 修饰,函数的实现可以不修饰。
-
假如有两个函数是通过.c(C语言)的方式进行实现的,那么在cpp的文件中,假如想使用这两个函数的话,不仅要声明,并且需要的在声明外要用 extern “C” 修饰。告诉编译器,这两个方法是用C语言来实现的。
-
当然也可以这么写
1 2 3
extern "C" { #include "math.h"//include的作用:把math.h的内容原封不动的拷贝一份。 }
-
那么一个函数声明既要给C调用又要给C++调用怎么办呢?用
__cplusplus
宏来判断你是否在C++的环境1 2 3 4 5 6 7 8 9
#ifdef __cplusplus extern "C" { #endif //这里是是你的声明或者代码,xxx #ifdef __cplusplus } #endif
3.防止重复include:
-
基于include只是执行了copy操作,所以include多次在语法上都没啥问题,但是代码量会增多,因此为了防止多次include
可以用以下代码:首次未定义才进入声明逻辑。
1
2
3
4
#ifndef ABC
#define ABC
xxx
- 或者可以用编译器的特性
#pragma once
来指名头文件只包含一次。
两者区别:第一种不受编译器的任何限制,是标准语法。第二种老编译器不支持,兼容性不够,只针对整个文件。
4.inline内联函数:本质把方法替换成具体实现,可以减少函数调用的开销,会增大代码体积会。但inline只是仅仅是建议编译器进行替换,有时候声明了也不一定起作用,比如:递归。递归是无法内联的。
内敛函数和宏都可以减少函数的开销,对比宏,内敛函数有函数的特性,有代码提示。
5.const:被修饰的变量不可修改
如果修饰的是类或者结构体,那么其中的成员也不可更改。
const修饰右边的东西
1
2
3
4
5
6
7
8
9
10
11
12
13
int age = 10;
int height = 20;
int *p = &age; //int * 是一个int指针 p是具体的值
*p = 20; //修改p指向的具体值
p = &height; //修改p的值
const int *p1 = &age;// p1是常量,*p1是常量,所以不能改年龄
int const *p2 = &age;// 和p1没区别
int * const p3 = &age;//p3是常量,*p3不是,因此可以年龄。
const int * const p4 = &age;//两个都不能改
int const * const p5 = &age;//两个都不能改
6.引用
在C++ 中,引用可以起到跟指针类似的功能,但指针可以修改,引用必须初始化,一旦指向了某个变量,就不可以再改变。
1
2
3
int age = 10
int &refAge = age;
age = 20;
价值:比指针更安全。因为指针在中途可以修改指向,引用不能。
本质:引用是弱化了的指针。本质是指针
7.this
通常一个对象的成员变量是在对象当中的,而函数是放在代码段的,为了在函数体内用this能访问到对象本身,这里有个一个隐式参数,把对象地址传入函数体中,然后将对象地址给this进行赋值
8.堆的申请和释放
new和delete或者new[]和delete[]必须成对出现
1
2
3
4
5
6
7
char *p = new char[4]; //申请连续的4个字节、*p指向第一个。char类型的数组
*p = "11";//给第一个字节赋值
*(p + 1) = "12"//给第二个字节赋值
delete[] p;
memset(p,1,4);//p的4个字节每一个字节都是1
9.析构函数
对象销毁时,进行调用,通过malloc分配的对象free时不会调用析构函数,声明为pulic才能被外界正常使用。
构造方法的顺序和析构的顺序相反。
构造函数: 父类构造->子类构造
析构函数: 子类析构->父类析构
10.多态
定义:同一操作作用于不同的对象,可以有不同的解释,产生不同的执行结果。
方法的调用,默认看指针类型进行操作,不看实际的对象类型是什么。
很多语言默认支持多态,C++要实现多态,需要用到虚函数。
11.虚函数
定义:被virtual修饰的成员函数
只要在父类中声明为虚函数,子类中重写的函数也自动变成虚函数(子类可以省略virtual关键字)
1.有虚函数存在一个类顶部会多4个字节,这个4个字节存放的是虚表(虚函数表)的地址,虚表里面有每个虚函数的方法地址。
2.所有对象共用一张虚表。(如果是多继承就多张虚表)
3.因此如果父类指针指向子类对象,析构函数也应该定义为虚函数。否则释放时无法调用子类的虚函数。
12.模版
模版的本质类似范型,编译器会为多类型的入参生成多个类型的函数。
13.类型转换
static_cast:普通转换,不支持交叉转换。
dynamic_cast:支持交叉转换,会做安全计算。
reinterpret_cast:简简单单的二进制复制。
const_cast:把const转换成非const。
14.nullptr可以解决NULL的二义性(既代表0又代表空指针)
15.智能指针
传统指针存在的问题:
1.需要手动管理内存。
2.容易发生内存泄漏。
3.释放之后产生野指针。
智能指针可以解决这些问题。
实现原理类似于装箱和拆箱,用一个内部私有指针保存对象。在释放时,自动释放私有的内部指针。