五、专题一经典问题解析
2017-01-03 00:51
106 查看
问题一、const与引用之间的疑惑
先总结:1.只有字面量初始化的const常量才会进入符号表(如const int a = 1; 1是字面量)
对const常量取引用(相当于取地址)会导致编译器为其分配空间,但空间里的值不会被使用
使用其他变量初始化的const常量仍然是只读变量(如 int a =4; const b = a; 最后b是只读变量)
2.被volatile修饰的const常量不会进入符号表
退化为只读变量,每次访问都从内存中取值
3.const引用的类型与初始化变量的类型
相同时:使初始化变量成为只读变量
不同时:生成一个新的只读变量,其初始值与初始化变量相同
1.
#include<stdio.h> int main() { const int x = 1; int& rx = const_cast<int &>(x);//一定要注意const_cast 只能用于指针或者引用的转换 rx = 5; printf("%d\n",x); printf("%d\n",rx); printf("%p\n",&x); printf("%p\n",&rx); getchar(); return 0; }
最后打印x的值为1,rx的值为5,两者的地址都一样
理由:对常量取引用就相当于取地址,都会分配空间,但不会用空间里面的值
2.
#include<stdio.h> int main() { volatile const int x = 1;//只读变量 int *p; p = const_cast<int *>(&x);//一定要注意const_cast 只能用于指针或者引用的转换 *p = 5; printf("%d\n",x); printf("%d\n",*p); printf("%p\n",&x); printf("%p\n",p); getchar(); return 0; }
结果打印的值都为5,地址值也一样
理由:被volatile修饰的const常量不会进入符号表,退化为只读变量,每次访问都从内存中取值
3.
#include<stdio.h> int main() { char c= 'c'; char& rx = c; const int& trx = c;//两边类型不同,变成只读变量 c = 'a'; printf("%c\n", c); printf("%c\n", rx); printf("%c\n", trx); getchar(); return 0; }
结果c和rx的值都为字符a,这很容易理解,因为只是简单 的引用,但trx的值却为字符c
理由:const引用的类型与初始化变量的类型
相同时:使初始化变量成为只读变量
不同时:生成一个新的只读变量,其初始值与初始化变量相同
问题二、引用与指针的疑惑
1.指针是一个变量,其值为一个内存地址,通过指针可以访问对应内存地址中的值而引用只是一个变量的新名字,所有对引用的操作(赋值,取地址等)都会传递到其引用的变量上
2.指针可以被const修饰成变量或者只读变量,const引用使其引用的变量具有只读属性
3.指针就是变量,不需要初始化,也可以指向不同的地址,引用必须在定义时初始化,之后无法再引用其他变量
引用的本质就是指针常量?
从c++的角度:
引用与指针常量没有任何关系
引用是变量的新名字,操作引用就是操作对应的变量
从c++编译器的角度来看:
为了支持新概念,“引用”必须要一个有效的解决方案
在编译器内部。使用指针常量来实现“引用”
因此“引用在定义时必须初始化”
答案:在进行c++编程时,直接站在引用的角度看,与指针毫无关系
分析bug时,站在c++编译器角度看
问题三、重载的疑惑
C++编译器对字面量的处理方式整数型字面量的默认类型为int,占用4个字节
浮点型字面量的默认类型为double,占用8个字节
字符型字面量的默认类型为char,占用1个字节
字符串型字面量的默认类型为const char*,占用4个字节
当使用字面量对变量进行初始化或赋值时
无溢出产生:编译器对字面量进行默认类型转换
产生溢出:编译器会做截断操作,并产生警告
#include <stdio.h> int main() { printf("sizeof(\'1\') = %d\n", sizeof('1')); printf("sizeof(2) = %d\n", sizeof(2)); printf("sizeof(3.0) = %d\n", sizeof(3.0)); char c = '1'; short s = '1'; int i = '1'; long l = '1'; long long ll = '1'; c = 2;//这里编译器居然没有报错,但如果换成2000时就会发生溢出错误 s = 2; i = 2; l = 2; ll = 2; float f = 0; double d = 0; f = 3.0; d = 3.0;
深入理解重载规则
精确匹配实参
通过默认类型转换匹配实参
通过默认参数匹配实参
三条规则会同时对已存在的重载函数进行挑选
当实参为变量并能够精确匹配形参时,不再进行默认类型转换的尝试。
当实参为字面量时,编译器会同时进行精确匹配和默认类型转换的尝试。
所以以下程序用字面值直接调用时因为有默认类型转换,有些编译器可能不知道应该调用哪个程序从而报错
#include <stdio.h> void func(int a, int b) { printf("void func(int a, int b)\n"); } void func(int a, char b) { printf("void func(int a, char b)\n"); } void func(char a, int b) { printf("void func(char a, int b)\n"); } void func(char a, char b) { printf("void func(char a, char b)\n"); } int main() { int a = 1; char b = '2'; func(a, a); func(a, b); func(b, a); func(b, b); func(1, 2); func(1 '2'); func('1', 2); func('1', '2'); return 0; }
a50c
问题四、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); printf("ri = %d\n", ri); } } 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; }
以上程序用c的方式编译时,代码里边又有c++的语句,居然也能编译通过,原因是
extern “C”告诉编C++译器将其中的代码进行C方式的编译
C方式的编译主要指按照C语言的规则对函数名进行编译
函数名经过编译后可能与源码中的名字有所不同
C++编译器为了支持重载,函数名经过编译后会加上参数信息,因而编译后的函数名与源码中完全不同
C编译器不会在编译后的函数名中加上参数信息
所以方式编译的函数名都一样,而c++的会加上参数的信息
一定注意:
extern “C”中的重载函数经过C方式编译后将得到相同的函数名,因此extern “C”中不允许重载函数,但extern “C”中的函数可以与extern “C”之外的函数进行重载。
相关文章推荐
- c++学习笔记(5.专题一经典问题解析)
- 专题一经典问题解析-7
- c++学习笔记(10.专题二经典问题解析)
- c++学习笔记(13.专题三经典问题解析)
- 专题二经典问题解析_13
- 5、专题一经典问题解析
- 专题一之经典问题解析
- c++学习笔记(17.专题四经典问题解析)
- 深入解析:分布式系统的事务处理经典问题及模型
- 深入解析:分布式系统的事务处理经典问题及模型
- ActiveX控件经典问题解析(转)
- 八个经典问题解析
- ZigZag排列问题与经典笔试面试题目解析
- C++学习笔记10 经典问题解析
- 搜索入门之dfs--经典的迷宫问题解析
- 递推专题 - 两种状态互推问题:经典问题 打砖块 + NOIP2015 Day2 T2
- 经典过桥问题的思路解析
- 【DP】经典问题解析
- 深入解析:分布式系统的事务处理经典问题及模型
- 八个经典问题解析