C中的命名空间
在C语言中只有一个全局作用域
C语言中所有的全局标识符共享同一个作用域
标识符之间可能发生冲突
C++中的命名空间
命名空间将全局作用域分成不同的部分
不同命名空间中的标识符可以同名而不会发生冲突
命名空间可以相互嵌套
全局作用域也叫默认命名空间三种使用方式
int a = 10;
方式一: std::out<<” a = “<< a << std::endl;
方式二: 加using std::out声明
方式三: 在全局区加 using namespace std;
//这样声明可以让整个程序都可以使用命名空间中的变量定义
//如果该声明放在函数中,则仅本函数有效
//只能定义在全局区,不能在函数中定义namespace
namespace spaceA
{
int id;
namespace spaceB
{
struct Student
{
int id;
char name[64];
};
}
namespace spaceC
{
struct Student2
{
int id;
char name[64];
};
}
}
1) 当使用
的时候,该头文件没有定义全局命名空间,必须使用namespace std;这样才能正确使用cout。若不引入using namespace std ,需要这样做。std::cout。
2) C++标准为了和C区别开,也为了正确使用命名空间,规定头文件不使用后缀.h.
3) C++命名空间的定义: namespace name { … }
4) using namespace NameSpaceA;
5) namespce定义可嵌套。
C变量使用时必须提前定义
C:
int i = 0;
for(i=0;i<10;++i);
C++:
for(int i=0;i<10;++i);
//C语言中的变量必须在作用域开始前定义
//C++更强调“实用性”,所有变量都可以在使用时定义
C:全局区
int g_a ;//自动初始化为0
int g_a = 10;//OK,这句会被解释为g_a = 10;
//C语言中多个同名的全局变量最终会被链接到全局数据区的同一个地址空间上
C++:
int g_a ;//自动初始化为0
int g_a = 10;//ERROR,重定义
C:
struct Student
{
int id;
}Student;
struct Student st1;//C定义时需要写struct关键字
st1.id = 10;
C++:
struct Student
{
int id;
}Student;
Student st1;
//C++可以不写,它把Student当做一个类型
//当然如果自己的代码在C与C++之间来回切换,最好是按C风格来
st1.id = 10;
//C语言的struct定义了一组变量的集合,C编译器并不认为这是一种新的类型
//C++中的struct是一个新类型的定义声明
C:
foo() { return 0;}
//C语言中函数没有返回值,默认返回int 型
C++:
// foo() { return 0;}//error
//必须给它写明返回类型
int foo() {return 0;}
C:
int fun1(int a)
{
return 0;
}
fun1(1,2,3,4,5);//OK
C++: //这样不对照函数声明的参数列表写,编译器会报错
int fun1(int a)
{
return 0;
}
//fun1(1,2,3,4,5);//ERROR
//函数f的返回值是什么类型,参数又是什么类型? 函数又可以接受多少个参数?
bool flag = true;
//真为1,假为0,有且仅有这两个值,sizeof(flag) ==1;
flag = 20;
cout<<"flag ="<//输出为1
flag = -30;
cout<<"flag ="<//输出为1
C:
int main(void)
{
int a = 10;
int b = 20;
//返回一个最小数 并且给最小数赋值成30
//三目运算符是一个表达式 ,表达式不可能做左值
//(a < b ? a : b ) = 30; //error
//因为C中的三目运算符返回的是一个常量数值,比如10,常量值是不能作为左值而被赋值的
//但可以这样
*(a50;
printf("a = %d, b = %d\n", a, b);
return 0;
}
C++: //三目运算符返回一个引用
#include
using namespace std;
int main(void)
{
int a = 10;
int b = 20;
//三目运算符是一个表达式 ,表达式不可能做左值
(a < b ? a : b ) = 30;
//返回一个变量,可以给该变量赋值
printf("a = %d, b = %d\n", a, b);
return 0;
}
1). C语言返回变量的值, C++语言是返回变量本身
C语言中的三目运算符返回的是变量值,不能作为左值使用
C++中的三目运算符可直接返回变量本身,因此可以出现在程序的任何地方
2). 注意:三目运算符可能返回的值中如果有一个是常量值,则不能作为左值使用(a < b ? 1 : b )= 30;
3). C语言如何支持类似C++的特性呢? *(a
1).
C中的const变量时一个冒牌货,它可以通过万能的指针进行修改
const int a = 10;
int *b = &a;
*b = 30; //这里常量a就被修改了
C++中
const int a = 10;
int *b = (int *)&c;//需要将const int *强转为int *类型
*b = 30;
/*
C++中const int a = 10;是将a分配在文字常量区中的“字符表”中
字符表中是以key -->value的形式存储的
而int *p = (int *)&a;是编译器在“编译”阶段临时在栈区分配一块int temp;空间
将a在字符表中对应的value拷贝到temp中
然后将temp的地址赋给指针p,接着p修改临时变量temp 的值
*/
2).
/*
在C++中可以用常量定义数组的长度,因为在C++中常量是真正不可修改的,在编译期间能从字符表中获取其value值
在C中const int a =10 ;这个常量只是个修饰符,可以通过指针修改,在编译阶段无法确定其值,所以不能这么定义数组
*/
C
const int a = 10;
int arr[a]={0};//error
//在C中定义数组需要知道数组的长度,而传进去的a在编译阶段是不知道的
C++
const int a = 10;
int arr[a]={0};//OK
//在C++中常量a在编译阶段就能知道了,所以可以这样定义数组
//在const修饰的常量编译期间,就已经确定下来了
3).
C++中的const常量类似于宏定义(相同点)
const int c = 5; 类似 #define c 5
C++中的const常量与宏定义的不同(不同点)
const 常量是由编译器处理的,提供类型检查和作用域检查
宏定义由预处理器处理的,单纯的文本替换
4).
C语言中的const变量
C语言中const变量是只读变量,有自己的存储空间
C++中的const常量
可能分配存储空间,也可能不分配存储空间
当const常量为全局,并且需要在其它文件中使用,会分配存储空间
当使用&操作符,取const常量的地址时,会分配存储空间
当const int &a = 10; const修饰引用时,也会分配存储空间
C:
enum MyEnum{ONE,TWO ,THREE ,FOUR ,FIVE};
void fun()
{
enum MyEnum e1 = 1;
if(e1 == 1)//这样写让程序可读性太差
return;
}
C++
enum MyEnum{ONE,TWO ,THREE ,FOUR ,FIVE};
void fun()
{
enum MyEnum e1 = 1;
//error
//if(e1 == 1)
//return;
if(e1 == TWO)//必须这么写,程序可读性提高
return;
}
//c 语言中枚举本质就是整型,枚举变量可以用任意整型赋值。而c++中枚举变量,只能用被枚举出来的元素初始化
函数参数:值传递
void swap(int a,int b)
{
int temp = a;
a = b;
b = temp;
}
函数参数:地址传递
void swap(int *a,int *b)
{
int temp = *a;
*a = *b;
*b = temp;
}
函数参数:引用传递
//应用能够在一定条件下取代指针的操作
void swap(int &a,int &b)
{
int temp = a;
a = b;
b = temp;
}
注意:
引用一经定义,必须初始化;
可对引用再进行引用
&在数据类型的后面表示定义引用,&前面没有数据类型表示取地址
1).
//变量名,本身是一段内存的引用,即别名(alias).引用可以看作一个已定义变量的别名
int a = 10;
int &b = a;
引用的性质:在定义时必须进行初始化,可以修改引用的值,但不可以将该引用应用于另一个变量
常指针的性质:int * const p;指针定义时必须初始化,可以修改指向的内存,但不可以修改指针的指向
其实在C++的内部实现中,引用是通过常指针来实现的
2).
struct A
{
int &a;
};
struct B
{
int *p;
};
cout<<"sizeof(struct A)"<<sizeof(struct A)<//4字节
cout<<"sizeof(struct B)"<<sizeof(struct B)<//4字节
//引用所占用的空间大小与指针相同
3).
void Modify(int *const a) //int *const a = main::&a;
{
*a = 200;
}
void Modify2(int &a)
//int &a = main::a,当我们进行函数参数传递时,编译器替我们,将实参的地址传递给引用
//int &a = main::&a
{
a = 100;
//对一个引用进行赋值操作时,编译器自动为我们隐藏*操作(类比常指针的赋值操作)
}
main::
int a = 0;
Modify(&a);
Modify2(a);
//如果我们在研究引用的时候,我们可以将引用当成一个常指针
//当我们在使用引用编程的时候,我们只需要将引用看成是变量的一个别名就可以了
引用作为返回值,不返要回局部变量的引用
int & getMem()
{
int a = 10;
return a;//1.int temp = a; 2. return temp//将temp的引用返回
}
main::
int &re = getMem();
int a = getMem();//一个值拷贝的过程,a = temp;
//getMem()实际上是做了int &temp = a; int &re = temp;
//但返回一个临时变量的引用,它在int &re = getMem()完成后就被释放掉了,这是一个危险的操作
**引用如果当函数返回值的话,返回一个引用,那么函数可以当成一个左值 **
int & getMem()
{
static int a =10;
return a;
}
getMem()=100;
struct teacher
{
int id;
char name[64];
};
//通过引用创建一个结构体对象
int get_mem (struct teacher ** tpp )
{
struct teacher * tp = NULL;
tp = ( struct teacher*) malloc(sizeof (struct teacher ));
if ( tp == NULL) {
return -1;
}
tp-> id = 100;
strcpy(tp ->name , "li4" );
* tpp = tp;
return 0;
}
//通过创建一个指针引用来创建一个结构体对象
int get_mem2 (struct teacher * &tp )
{
tp = ( struct teacher*) malloc(sizeof (struct teacher ));
if ( tp == NULL) {
return -1;
}
tp-> id = 300;
strcpy(tp ->name , "wang5" );
return 0;
}
int main (void )
{
struct teacher * tp = NULL;
get_mem(& tp);
cout << "id =" << tp ->id << ", name = " << tp ->name << endl;
free_teacher(& tp);
cout << "---------------" << endl ;
get_mem2( tp);
cout << "id =" << tp ->id << ", name = " << tp ->name << endl;
free_teacher2(tp );
system("pause" );
return 0;
}
//-------------------------------
struct teacher * tp = NULL;
int get_mem2 (struct teacher * &tp );
struct teacher * &tp ----> int &tp性质一样
struct teacher *就是一个类型名,给struct teacher *的变量起一个别名:tp
const int a = 10;
//如果对一个const变量进行引用,必须是const 引用
const int & re = a;
//---------冷知识-----------
const int &re3 = 10;
//这一步执行完后并不是意味着const int &re3 = &10;10是没有地址的,也是不可修改的,唯一能修改的是
//编译器自动在栈区开辟了一个空间temp,将temp = 10 ;
//然后const int &re3 = temp;
const int *p = &re3;
//p拿到temp的地址
*((int *)p) = 30;//(特殊情况·无敌强转)
//强制转换后通过p来修改了temp 的值
cout<<"*p = "<<*p<//30
cout<<"re3 = "<//30