您的位置:首页 > 其它

经典问题解析(1)---const和引用、指针与引用、函数重载、C方式编译

2017-02-21 21:41 330 查看

const和引用

#include <stdio.h>

int main()
{
const int x = 1;//定义的一个const常量
const int& rx = x;//当const常量取地址时,编译器会为其分配一个空间
//在下面的程序中,x仍为符号表中的常量,rx则为新分配空间中的数值
int& nrx  = const_cast<int&>(rx);//类型转换将const属性去掉,变为普通引用

nrx = 5;

printf("x = %d\n", x);//打印 1
printf("rx = %d\n", rx);//打印 5
printf("nrx = %d\n", nrx);//打印 5
printf("x = %p\n", &x);//打印的是分配空间的地址
printf("rx = %p\n", &rx);//三个地址相同
printf("nrx = %p\n", &nrx);

volatile const int y = 2;
//由于volatile,y不是一个真正的常量,只是只读变量
int* p = NULL;

p = const_cast<int*>(&y);//y的地址给p
*p = 6;

printf("y = %d\n", y);//两个的输出结果都为6
printf("*p = %d\n", *p);

const int z = y;//使用其它变量初始化的const常量仍然是只读变量

p = const_cast<int*>(&z);
*p = 7;

printf("z = %d\n", z);//两个的输出结果都为7
printf("*p = %d\n", *p);

char c = 'c';
char& rc = c;
const int& trc = c;
//const引用的类型与初始化变量的类型不同,
//生成一个新的只读变量,其初始值与初始化变量相同

rc = 'a';

printf("c = %c\n", c);//输出结果为a,a,c
printf("rc = %c\n", rc);
printf("trc = %c\n", trc);

return 0;
}


符号表:

符号表是编译器在编译过程中产生的关于源程序中语法符号的数据结构,如常量表、变量名表、数组名表、函数名表等等。

符号表是编译器自用的内部数据结构,符号表不会进入最终产生的可执行程序中。



指针与引用

#include <stdio.h>

struct SV
{
int x;
int y;
int z;
};

struct SR
{
int& x;
int& y;
int& z;
};

int main()
{
SV sv = {1, 2, 3};
SR sr = {sv.x, sv.y, sv.z};

printf("&sv = %p\n", &sv);// &sv = &sv.x
printf("&sv.x = %p\n", &sv.x);//依次增加4
printf("&sv.y = %p\n", &sv.y);
printf("&sv.z = %p\n", &sv.z);

printf("&sr = %p\n", &sr);//打印出的是另外的地址
printf("&sr.x = %p\n", &sr.x);//&sr.x =  &sv.x
printf("&sr.y = %p\n", &sr.y);//&sr.y =  &sv.y
printf("&sr.z = %p\n", &sr.z);//&sr.z =  &sv.z
//操作引用就等于操作变量

SV& rsv = sv;

rsv.x = 4;
rsv.y = 5;
rsv.z = 6;

printf("sv.x = %d\n", sv.x);//打印结果为4,5,6
printf("sv.y = %d\n", sv.y);
printf("sv.z = %d\n", sv.z);
//操作引用就等于操作变量

return 0;
}


指针与引用的区别:

指针是一个变量,其值为一个内存地址,通过指针可以访问对应内存地址中的值。

引用不是变量只是一个变量的新名字,所有对引用的操作(赋值,取地址等)都会传递到其引用的变量上。

指针可以被const修饰成为常量或者只读变量。

const引用使其引用的变量具有只读属性。

指针就是变量,不需要初始化,也可以指向不同的地址。

引用天生就必须在定义时初始化,之后无法在引用其它变量。

从使用C++语言的角度来看:

引用与指针常量没有任何的关系。

引用是变量的新名字,操作引用就是操作对应的变量。

从C++编译器的角度来看:

为了支持新概念“引用”必须要一个有效的解决方案,在编译器内部,使用指针常量来实现“引用”。

因此“引用”在定义时必须初始化。



重载的相关问题

#include <stdio.h>

void func(int a, int b)//重载1号函数
{
printf("void func(int a, int b)1\n");
}

void func(int a, char b)//重载2号函数
{
printf("void func(int a, char b)2\n");
}

void func(char a, int b)//重载3号函数
{
printf("void func(char a, int b)3\n");
}

void func(char a, char b)//重载4号函数
{
printf("void func(char a, char b)4\n");
}

int main()
{
int a = 1;
char b = '2';

func(a, a);//调用重载1号函数
func(a, b);//调用重载2号函数
func(b, a);//调用重载3号函数
func(b, b);//调用重载4号函数

//当采用字面量如1,2来调用重载函数时,要看编译器的字面量的默认类型是什么,可能不能调用
func(1, 2);     //调用重载1号函数
func(1, '2');   //调用重载2号函数
func('1', 2);   //调用重载3号函数
func('1', '2'); //调用重载4号函数

return 0;
}


C++编译器对字面量的处理方式:

整数型字面量的默认类型为int,占用4个字节

浮点型字面量的默认类型为double,占用8个字节

字符型字面量的默认类型为char,占用1个字节

字符串型字面量的默认类型为const char*,占用4个字节

当使用字面量对变量进行初始化或赋值时:

无溢出产生:编译器对字面量进行默认类型转换。

产生溢出:编译器会做截断操作,并产生警告。

深入理解重载三规则:

精确匹配实参

通过默认类型转换匹配实参

通过默认参数匹配实参

函数重载的判断标准有:

函数名称、参数类型、参数个数、const

如果同时在类中,对于函数名相同的const函数和非const函数能够构成重载。

如果定义的对象是常对象,则调用的是const成员函数;如果定义的对象是非常对象,则调用重载的非const成员函数。

三条规则会同时对已存在的重载函数进行挑选

当实参为变量并能够精确匹配形参时,不再进行默认类型转换的尝试。

当实参为字面量时,编译器会同时进行精确匹配和默认类型转换的尝试。

不同的编译器可能有不同的处理结果。

C方式编译

#include <stdio.h>
extern "C"
{
void func(int x)
{
const int i = 1;
int& ri = const_cast<int&>(i);
ri = 5;
printf("i = %d\n", i);//输出1
printf("ri = %d\n", ri);//输出5
}
}
void func(const char* s)
{
printf("%s\n", s);
}
int func(int a, int b)
{
return a + b;
}
int main()
{
func(1);
func("Delphi Tang");
func(1, 2);
return 0;
}


上面程序输出的结果为 i = 1, ri = 5, Delphi Tang,

说明extern “C”中的代码仍然按照C++的方式进行编译的。



C方式的编译主要指按照C语言的规则对函数名进行编译。而函数中的函数体的代码仍然会按照C++的方式进行编译。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐