a. 想使用的时候才定义变量
b. for循环中定义变量:for(int i;
2. 数据类型-
bool :
a. 相应新增true、false保留字
b. 输出0和1
-
class
-
&(引用)
- void指针可以指向任意类型的数据,即可以用任意类型的指针对void指针赋值。例如:
int *pint ;
void *pvoid ; //它没有类型,或者说这个类型不能判断出指向对象的长度
pvoid = pint ; //只获得变量/对象地址而不获得大小,即pvoid的指针类型还是没有转变
//但是不允许 pint=pvoid;
printf("%d",*pint); //正确
printf("%d",*pvoid); //错误,pvoid不是指向某类型的指针
printf("%d",*(int *)pvoid); //正确,同printf("%d",*pint);
-
在C语言中,可以把任何类型的指针(包括函数指针)赋值给void*指针而无须进行强制类型转换。
在C++中,对这个转换做了更严格的限制:只有非 常量指针才能赋值给void*指针。
C++示例代码:const char pp[10] = {0}; const char* str = "aaa"; //pp与str均为指向常量区的指针 void* pv = NULL; pv = pp;//错误,不能将常量指针赋值给void *指针 pv = str;//错误,不能将常量指针赋值给void *指针 -
如果要将pvoid赋给其他类型指针,则需要强制类型转换如:
pint = (int *)pvoid; //转换类型也就是获得指向变量/对象大小
-
void指针在强制转换成具体类型前,不知道指向对象的(字节)大小,不能解引用(即取内容的意思);
【Eg】 void *pvoid=pint;
*pvoid //错误;
-
void指针不能参与指针运算,除非进行转换。
只知道地址,不知道指针类型(大小),
即:参与运算的指针必须是确定知道其指向数据类型大小的。
-
void指针的应用
当进行纯粹的内存操作的时候,或者传递一个指向未定类型的指针时,可以使用void指针;
典型的如内存操作函数memcpy和memset的函数原型分别为:
void * memcpy(void *dest,constvoid * src,size_tlen); void * memset(void * buffer,intc,size_tnum);
这样,任何类型的指针都可以传入memcpy和memset中,这也真实地体现了内存操作函数的意义,因为它操作的对象仅仅是一片内存,而不论这片内存是什么类型。
注意memcpy和memset函数返回的也是void*类型。
【注】:malloc函数的返回类型是void,**
int p =(int)malloc(100sizeof(int));
进行了强制性转化。
-
C++中 int(x)与(int)x意义相同,
而C中只有(int)x;
- 作用域小的变量覆盖作用域大的变量
- 用“::变量名”可以访问具有文件作用域的变量,但不能访问隐藏的局部变量
【Eg】:变量作用域:
#includeusing namespace std; int x=1; //全局作用域 void func() { int x=2; //局部变量,隐藏了全局变量 cout<<"局部变量"< 5. 引用类型& 引用本质上是一个指针常量int *const p;(存放的地址不能变,即:不能修改引用的值)
const int &a=10; //允许 int &b=10; //不允许在C++中值传递可以实现单向传递,但是引用传递可以实现双向传递。
引用类型
1. 引用(&)是标识符的别名
例如:int i, j ; int & ri = i; //定义int引用ri,并初始化为变量i的引用。
定义一个引用时,必须同时对他进行初始化,使它指向一个已存在的对象。【PS】:初始化时指向的这个对象只能是变量,不能是常量。
j = 10ri = j; //相当于是i=j
- 一旦一个引用被初始化后,就不能改为指向其他对象
- 可以取引用的地址
2. 用途:引用可以作为形参代替指针使用
若条件允许,就应将引用形参声明为const形参,这样可以避免无意间修改数据而导致编程错误。
若形参中无const修饰,则引用调用的实际参数只能是变量!(存在合理的地址空间)
形参有用const 修饰,则实参也可以是常量(N,‘A’等)。
即:使用const形参使得函数能够接受const和非const实参,否则只能处理非const数据。
void func1(int n) { //可以修改n,但值不会返回调用者} //可用值或变量调用 void func2(int &n){ //可以修改n,值会返回调用者} //只能用同类型的变量调用该函数 void func3(const int &n) { //根本就不允许修改n} //可用值或变量调用
- 返回引用类型:
- 返回引用必须保证返回的引用变量有合法的内存空间,并且不在函数的运行栈中。一般只能返回全局变量和静态变量或者函数传递的形式参数。
不能建立引用数组:
引用是需要初始化的,大数组初始化麻烦
破坏数组存放的连续性
int a[3];
int &b[3]=a; //错误,不能建立引用数组6. 从键盘读入字符串
- 不能建立引用的引用,不能建立引用的指针
char s[80]; cin>>s; //1.遇到空白停止 2.输入可能超过80个字符 cin.getline(s,80); //最多输入79个字符 cout<7. const 7.1只读函数int getMember() const;
表示不能改变对象的成员变量的值,也不能调用一个非const的成员函数(避免间接修改成员数据);
7.2 const与指针
- 指针不能指向常量(const 定义的常量)
#includeusing namespace std; int main() { const int N=10; int a[N]; //允许。在C++中,N是常量,而C中N是不能改变的变量 }
- const int *cp==int const *cp;
同为指向常量的指针(const int )**p,且cp可以指向其他普通变量,但是无法通过*cp来修改变量的值。
- int * const cp;
指针常量(这个指针是常量),不能指向其他地址,但是可以修改指向的内容。
8. 枚举、结构、联合类型
在C中,下述语句是错误的:(N是不能改变的变量)
const int N=10; //必须改为:#define N 10
int a[N];但在C++中,上述语句是允许的。(N是常量)
enum weekday {sun,mou,tue,wed,thu,fri,sat}; weekday a,b,c; //weekday也是一种类型 仅C++支持) //C语言中需要enum weekday a,b,c;结构与联合同上,可省去struct和union;
8.1枚举类型void test() {undefined enum Week { Mon, Tue, Wed, Thi, Fri, Sat, Sun }; enum Other { One, Two, Three }; enum Week week = Mon;C中:
允许非枚举值赋值给枚举类型, 允许其他枚举类型的值赋值给当前枚举类型
week = 100; //ok
week = One; //ok
枚举值具有外层作用域,容易造成名字冲突 int One = 100; //error
不同类型的枚举值可以直接比较
可以改变枚举元素的值
C++中:
8.2结构
C++ 只能允许赋值枚举值
// week = 100; //error
// week = One; //error
枚举元素会暴露在外部作用域,不同的两个枚举类型,若含有相同枚举元素,则会冲突
enum OtherWeek { Mon };
枚举元素是常量,不能改变
C语言结构体初始化,可以如下四种:
#includeint main(int argc, const char * argv[]) { //定义结构体类型 struct Person { char *name; int age; double heigth; }; //初始化的4种方式 //1.定义的同时初始化 struct Person p1 = {"zhangsan",20,170}; //2.先定义再逐个初始化 struct Person p2; p2.name = "ykd"; p2.age = 18; p2.heigth = 180; //3.先定义再一次性初始化 struct Person p3; p3 = (struct Person){"lisi",18,180}; //注意:结构体和数组在这里的区别,数组不能先定义再进行一次性初始化 //结构体要明确的告诉系统{}中是一个结构体 //4.指定将数据赋值给指定的属性 struct Person p4 = {.heigth=1.77, .name="wangwu", .age=33}; C++结构体初始化会更加丰富,有内置函数来执行。
当然也可兼容C语言上述四种。除此还有以下两种:
struct ListNode {
int val; struct ListNode *next; ListNode(int x) //链表初始化 { val = x; next = NULL; }};
struct ListNode {
int val;
struct ListNode *next;
ListNode(int x) /链表初始化
val(x), next(NULL) {}
};以上都可以采用ListNode a(1),b(2),c(3);直接初始化。
9. 函数 函数声明:如果你声明一个函数:int fun();
函数参数为空的时候,在c中的意思是函数参数不确定,而在c++中的意思是函数参数为空。
如果函数这样声明:int fun(void);,这时不论是在c中还是在c++中的意思都是函数参数为空。
默认参数函数重载
- 在函数声明处体现,定义中不能出现
- 默认参数只能放形参列表的最后
- 同名函数才有重载
- 根据函数的参数类型,数量,顺序进行重载,返回值不行
//第十一题 (函数重载) 源代码1 #includeusing namespace std; int func(int x) { cout<<"int x"< 3.关于函数重载时的自动类型转化
//第十一题 (函数重载) 源代码2 #includeusing namespace std; int func1(double x) //关于函数重载时的自动类型转化 { cout<<"double x"< 内联函数 //第九题 (内联函数) 源代码1 #include10.模板using namespace std; inline int add(int x,int y)//内联函数的声明和定义,inline加在定义处才有用 { return x+y; } inline void Foo(int x,int y); int main() { } void Foo (int x,int y)//仅在声明处出现inline,不构成内联函数 { } 11.抛出异常:
函数模板参数表中指明的类型参数必须用于函数参数表,例如:
template T f1() {……} //错误
template void f2()
{ //错误 T a;
……
}
模板函数的声明和定义必须放在同一个cpp下,否则连接器无法通过模板函数的声明找到相对应的定义 (模板未被实例化的时候是没有生成二进制代码的)
- 抛出异常类时,调用构造函数 (要加括号) //或者直接抛出该类的对象
#includeusing namespace std; void func(void); class Expt { //异常类 public: Expt() {cout<<"执行异常类的构造函数...n";} Expt(const Expt &e) { *this=e; cout<<"执行异常类的拷贝构造函数...n"; } ~Expt() {cout<<"执行异常类的析构函数...n";} const char *showReason() const { return "Expt类异常!n"; } }; class Demo { public: Demo() {cout<<"构造Demo...n";} ~Demo() {cout<<"析构Demo...n";} }; void func(void) { Demo dObj; cout<<"在函数func()中抛出Expt类异常!n"; throw Expt(); //不能写成:throw Expt; }



