代码疑云

代码疑云(1)-掌握初始化列表


代码

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5. private:  
  6.   int x1;  
  7.   int x2;  
  8. public:  
  9.   A():x2(1),x1(x2++){} //初始化列表  
  10.   void print()  
  11.   {  
  12.     cout<<"x1="<<x1<<endl  
  13.         <<"x2="<<x2<<endl;  
  14.   }  
  15. };  
  16. int main()  
  17. {  
  18.   A a;  
  19.   a.print();  
  20.   
  21.   return 0;  
  22. }  

:x1,x2最终被输出什么值呢?为什么?

解答:上机调试下会发现输出的结果是:x1是一个随机数,x2是1。为什么?因为在初始化列表中在给x1赋值为x2++时,这个x2并未初始化,也就是说x2里面什么东西也没装。也许你会问我不是在前面已经给x2赋值了吗,没错,但是有一个问题你忽略了,那就是初始化列表的赋值顺序是依照x1和x2的声明顺序的顺序来初始化的,也就是说在代码中,程序是先给x1赋值为x2++(此时x2并未初始化),再给x2赋值为1。还有初始化列表里的赋值,是在变量被声明时进行的,所以多使用初始化列表是可以提升程序效率的。

!!代码疑云系列由本人在天天唯C论坛下首发


代码疑云(2)-c函数调用约定

代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. void foo(int p1,int p2,int p3)  
  4. {  
  5.   cout<<"p1="<<p1<<endl  
  6.       <<"p2="<<p2<<endl  
  7.       <<"p3="<<p3<<endl;  
  8. }  
  9. int main()  
  10. {  
  11.   int i;  
  12.   cout<<"first call:"<<endl;  
  13.   i=0;  
  14.   foo(++i,++i,++i);  
  15.   cout<<"second call:"<<endl;  
  16.   i=0;  
  17.   foo(++i,i++,i++);  
  18.   return 0;  
  19. }  

:两次调用foo函数分别输出了什么,为什么?

解答:按照cedel函数调用的约定,编译器使参数从左到右的入栈。第一次调用为什么p1,p2,p3的值全是3呢,原因在此,在foo被call之前三++i 操作将先被操作也就是连续自增了3次,最终结果i 的值是3,然后是编译器push(i),push(i),push(i)三次入栈,然后call到foo定义处依次出栈并相应地复制给了形参。第二次调用foo时,一开始与第一次一样先是计算三次++操作,但是所不同的是最后两个是i++,i++ 刚没说到它们的计算顺序,编译器计算这些的顺序是由右到左的,也就是先i++,再i++,最后是++i,而运算i++是先取值再自增的,编译器会先把i (这时为0)存入寄存器(cpu中的存储器),再加1,然后计算下一个i++ 与前一次一样,所不同的是这次 i 的值是1,因为前面已加1 ,最后++i 。

!!代码疑云系列由本人在天天唯C论坛下首发



代码疑云(3)-静态字符串

代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. int main()  
  4. {  
  5.   char *str1 = "string";  
  6.   char *str2 = "string";  
  7.   if(str1 == str2)  
  8.     cout<<"str1 is same as str2";  
  9. }  

:str1 的值是否等于 str2 而输出字符串“str1 is same as str2”呢,为什么? 解答:是的 “str1 is same as srr2”,也就是说str1与str2指向了相同的内存地址,因为"string"是静态对象,是由编译器分配给他的内存空间,在代码中出现了两次,编译器并不会给他们分别分配空间,因为如果这样将会造成不必要的浪费。


代码疑云(4)-类的sizeof值

代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5.   
  6. };  
  7. class B  
  8. {  
  9.   char a;  
  10.   int b;  
  11. };  
  12. class C  
  13. {  
  14.   void foo(){};  
  15. };  
  16. class D  
  17. {  
  18.   virtual void foo(){};  
  19. };  
  20. int main()  
  21. {  
  22.   cout<<sizeof(A)<<sizeof(B)<<sizeof(C)<<sizeof(D);  
  23.   return 0;  
  24. }  

:结果是什么,为什么呢?

解答:sizeof(A)为1,而不是0,虽然空类没有任何成员变量,但其实体提供取地址操作,所以其内存空间不能为0。sizeof(B)为8,编译器在计算类体或结构体变量的地址时是通过字节对齐的方式进行的,也就是通过加多少偏移量来确认是那个变量。类的偏移量为其最大内存空间的类型的成员变量的长度,其最大内存空间类型成员是int,所以偏移量为4字节,即char a成员需要补上3个字节,才能让编译器准确高效地寻址,再加上int的4字节,sizeof(B)就是8了。sizeof(C)为1,类的成员函数在编译器编译时,其函数地址就已自动存放,所以不必为其分配额外的空间来存放他,所以它的长度跟空类一样为1。sizeof(D)为4,因为类D需要构造一虚函数列表来存放函数指针以实现动态调用,一个指针的长度占用4个字节,所以为4.


代码疑云(5)-类成员函数的thiscall约定

代码:

[cpp] view plaincopy
  1. #include<iostream>  
  2. using namespace std;  
  3.   
  4. class A  
  5. {  
  6. private:  
  7.   int value;  
  8. public:  
  9.   A()  
  10.   {  
  11.     value=0;  
  12.   }  
  13.   void coutHello()  
  14.   {  
  15.     cout<<"hello"<<endl;  
  16.   }  
  17.   void coutValue()  
  18.   {  
  19.     cout<<value<<endl;  
  20.   }  
  21. };  
  22. int main()  
  23. {  
  24.   A *pA=NULL; //空指针,所指向的内容不可访问存取  
  25.   
  26.   pA->coutHello();  
  27.   pA->coutValue();  
  28.   
  29.   return 0;  
  30. }  

(感谢网友提供的题目)

疑:调用coutHello和coutValue方法有什么问题?
解答: 成员函数的地址在编译器编译时给出的,所以是已知的,根据thiscall约定,类的成员函数在编译时编译器会传入一个this指针,通过this指针指向成员变量,在调用couthello时并未用到this指针所以调用正常,而调用coutvalue时,value需要用到this指针,因为此时this是NULL指针,所以会发生内存报错。



代码疑云(6)-头文件的正确定义

代码:

头文件print_tools.h

[cpp] view plaincopy
  1. #include<stdio.h>  
  2. void printStr(const char *pStr)  
  3. {  
  4.   printf("%s\n",pStr);  
  5. }  
  6. void printtInt(const int i)  
  7. {  
  8.   printf("%d\n",i);  
  9. }  

头文件counter.h
[cpp] view plaincopy
  1. #include"print_tools.h"  
  2. static int sg_value;  
  3. void counter_init()  
  4. {  
  5.   sg_value=0;  
  6. }  
  7. void counter_count()  
  8. {  
  9.   sg_value++;  
  10. }  
  11. void counter_out_result()  
  12. {  
  13.   printStr("the result is:");  
  14.   printtInt(sg_value);  
  15. }  

main.cpp
[cpp] view plaincopy
  1. #include "print_tools.h"  
  2. #include "counter.h"  
  3. int main()  
  4. {  
  5.   char ch;  
  6.   counter_init();  
  7.   printStr("please input some charactors:");  
  8.   while((ch=getchar())!='$')  
  9.     {  
  10.       if(ch=='A')  
  11. <span style="white-space:pre">    </span>counter_count();  
  12.     }  
  13.   counter_out_result();  
  14. }  

疑:以上代码编译时有何问题吗,是什么导致的呢?

解答:void printStr(const char*)和'void printtInt(int) 函数redefine了,道理很简单,因为在counter.h中已包含了print_tools.h,在main.cpp中又包含了print_tools.h头文件,也就是两次包含了print_toosl.h,所以也就发生了重定义错误,这是初学者常见问题,要避免这个问题,我们必须采取防范措施,就是使用预编译命令,如下作修改:

头文件print_tools.h

[cpp] view plaincopy
  1. #ifndef PRINT_TOOLS_H //如果未定义 PRINT_TOOLS_H  
  2. #define PRINT_TOOLS_H //则定义 然后编译以下源代码  
  3. #include<stdio.h>  
  4. void printStr(const char *pStr)  
  5. {  
  6.   printf("%s\n",pStr);  
  7. }  
  8. void printtInt(const int i)  
  9. {  
  10.   printf("%d\n",i);  
  11. }  
  12. #endif //结束 //如此改头文件就只被编译器编译一次了,起到了防范重定义错误的作用  

头文件counter.h
[cpp] view plaincopy
  1. #ifndef COUNTER_H  //  
  2. #define COUNTER_H  //  
  3. #include"print_tools.h"  
  4. static int sg_value;  
  5. void counter_init()  
  6. {  
  7.   sg_value=0;  
  8. }  
  9. void counter_count()  
  10. {  
  11.   sg_value++;  
  12. }  
  13. void counter_out_result()  
  14. {  
  15.   printStr("the result is:");  
  16.   printtInt(sg_value);  
  17. }  
  18. #endif //  

在一个工程项目中头文件众多繁杂,采用这个方法可以很好的避免,所以每当我们定义一个头文件时要养成如此的良好习惯。


代码疑云(7)-构造函数在类继承时

代码

[cpp] view plaincopy
  1. #include <iostream>  
  2. using namespace std;  
  3. class A  
  4. {  
  5. public:  
  6.   A()  
  7.   {  
  8.     Print();  
  9.   }  
  10.   virtual void Print()  
  11.   {  
  12.     cout<<"A is constructed.\n";  
  13.   }  
  14. };  
  15.   
  16. class B: public A  
  17. {  
  18. public:  
  19.   B()  
  20.   {  
  21.     Print();  
  22.   }  
  23.   
  24.   virtual void Print()  
  25.   {  
  26.     cout<<"B is constructed.\n";  
  27.   }  
  28. };  
  29.   
  30. int main()  
  31. {  
  32.   A* pA = new B();  
  33.   delete pA;  
  34.   
  35.   return 0;  
  36. }  
(感谢网友提供的题目)

以上代码输出结果是?

输出结果如下:
A is constructed.
B is constructed.
解释:当new B()时,因为B继承了A,所以编译器首先调用A的构造函数,A的构造函数里是调用A类里的Print(),所以首先输出A is constructed ,然后调用的是B的构造函数,此时Print虚函数指针已指向B的void print(),所以输出B is constructed。





本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/453276.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

网络拥塞

拥塞&#xff08;Congestion&#xff09;指的是在包交换网络中由于传送的包数目太多&#xff0c;而存贮转发节点的资源有限而造成网络传输性能下降的情况。拥塞的一种极端情况是死锁&#xff08;Deadlock&#xff09;&#xff0c;退出死锁往往需要网络复位操作。

android 多线程future,多线程FutureTask的使用方法和使用实例

FutureTask是一种可以取消的异步的计算任务。它的计算是通过Callable实现的&#xff0c;它等价于可以携带结果的Runnable&#xff0c;并且有三个状态&#xff1a;等待、运行和完成。完成包括所有计算以任意的方式结束&#xff0c;包括正常结束、取消和异常。Future有个get方法而…

2017.12.26

转载于:https://www.cnblogs.com/dyh-air/p/8118961.html

mac 下安装pip

pip是常用的python包管理工具&#xff0c;类似于java的maven。用python的同学&#xff0c;都离不开pip。 在新mac中想用home-brew安装pip时&#xff0c;遇到了一些小问题&#xff1a; bogon:~ wanglei$ brew install pip Error: No available formula with the name "pip&…

IT职场人生系列

IT职场人生系列之一&#xff1a;序言及找谁占卜 本文是IT职场人生系列的第一篇。 时间流逝&#xff0c;渐渐从之前在公司里边的小弟变成大哥了&#xff0c;当年身边比我大的程序员们都不见了&#xff0c;既没有当领导也没有去创业&#xff0c;就这么消失了。 年轻的程序员或…

RS-232协议

计算机与计算机或计算机与终端之间的数据传送可以采用串行通讯和并行通讯二种方式。由于串行通讯方式具有使用线路少、成本低&#xff0c;特别是在远程传输时&#xff0c;避免了多条线路特性的不一致而被广泛采用。 在串行通讯时&#xff0c;要求通讯双方都采用一个标准接口&am…

linux sed 找出前后三行,Linux Sed 使用示例

环境&#xff1a;CentOS鉴于语句描述苍白无力&#xff0c;用例子直接说明。mytxt文件内容&#xff1a;zilzhang 19881110 jiangxi 18 filmzhagnsan 21321 sichuan 100 cardlisi 3435 hunan 65 TV1. 找出文件第二行$ sed -n ‘2p‘ mytxtzhagnsan 21321 sichua…

MessageBox 弹框

模拟系统的消息提示框而实现的一套模态对话框组件&#xff0c;用于消息提示、确认消息和提交内容。 从场景上说&#xff0c;MessageBox 的作用是美化系统自带的 alert、confirm 和 prompt&#xff0c;因此适合展示较为简单的内容。如果需要弹出较为复杂的内容&#xff0c;请使用…

什么是同轴电缆

同轴电缆从用途上分可分为基带同轴电缆和宽带同轴电缆&#xff08;即网络同轴电缆和视频同轴电缆&#xff09;。同轴电缆分50Ω 基带电缆和75Ω宽带电缆两类。基带电缆又分细同轴电缆和粗同轴电缆。基带电缆仅仅用于数字传输&#xff0c;数据率可达10Mbps。同轴电缆(Coaxial Ca…

android textview表情,Android开发(16)-TextView显示表情图像和文字

从这个案例中我们可以学到当我们美化图片美化界面的时候可以在某一区域输入图片和文字混搭信息,第三张图片按比例缩小&#xff0c;第四张图像有超链接布局文件MainActivity.javapackage com.example.textview3;import java.lang.reflect.Field;import android.os.Bundle;import…

Rating

题目链接 题意&#xff1a; 起始状态是&#xff08;0。0&#xff09;&#xff0c;每次转移的时候都是对两个数中的较小的数操作。1&#xff09;以概率p转向&#xff08;min&#xff08;a 50&#xff0c;1000&#xff09;。b&#xff09; 2&#xff09;以概率1-p转向&#x…

linux的apache2.4限定某个目录禁止解析PHP及user_agent与PHP相关配置

限定某个目录禁止解析PHP 对于使用PHP语言编写的网站&#xff0c;有一些目录是有需求上传文件的&#xff0c;比如服务器可以上传图片&#xff0c;并且没有做防盗链&#xff0c;所以就会被人家当成了一个图片存储服务器&#xff0c;并且盗用带宽流量。如果网站代码有漏洞&#x…

什么是光缆

光缆(optical fiber cable)是为了满足光学、机械或环境的性能规范而制造的&#xff0c;它是利用置于包复护套中的一根或多根光纤作为传输媒质并可以单独或成组使用的通信线缆组件。光缆主要是由光导纤维&#xff08;细如头发的玻璃丝&#xff09;和塑料保护套管及塑料外皮构成&…

js调用android播放器,js调用android本地方法

8种机械键盘轴体对比本人程序员&#xff0c;要买一个写代码的键盘&#xff0c;请问红轴和茶轴怎么选&#xff1f;昨天自己录了一个android本地调用h5中js方法&#xff0c;可能是因为视频比较耗费流量&#xff0c;结果看的人不是很多&#xff0c;所以决定还是先写文章&#xff0…

linux之分区的水深(标准分区方式)

1.首先创建boot分区(200M即可) boot分区作为linux启动相关信息的存储介质&#xff0c;不论boot分区什么时候&#xff0c;它都会排在整个硬盘的起始段&#xff0c;方便系统启动获取相关信息&#xff0c;用户尽量不去更改boot分区的挂载点顺序。 2.接着创建swap分区&#xff08;应…

doxygen相关问题

doxygen相关问题 我主要的设置有 现在 wizard对话框中大体设置下,然后 export设置: project->DOXYFILE_ENCODINGGBK project->OUTPUT_LANGUAGEchinese input->INPUT_ENCODINGGBK Dot->HAVE_DOT Dot-> UML_LOOK Dot->CALL_GRAPH Dot->CALLER_GRAPH http…

前端之JavaScript 02

一、函数 // 最基础的函数定义 function f1() {console.log(hello world!); } f1(); // hello world!// 带参数的函数 function f2(name,age) {console.log("姓名 : " name " 年龄&#xff1a;" age); } f2("jassin",18); // 姓名 : jassi…

什么是双绞线

双绞线&#xff08;twisted pair&#xff0c;TP&#xff09;是一种综合布线工程中最常用的传输介质&#xff0c;是由两根具有绝缘保护层的铜导线组成的。把两根绝缘的铜导线按一定密度互相绞在一起&#xff0c;每一根导线在传输中辐射出来的电波会被另一根线上发出的电波抵消&a…

Android蒙版倒计时,【倒计时海报设计】- 虎课网

我们在大街上经常会看到各种宣传海报&#xff0c;有时商家为了达到促销的目的会在醒目的地方张贴一张倒计时海报&#xff0c;为的就是吸引群众的眼睛&#xff0c;大家了解PS倒计时海报设计的制作过程吗&#xff1f;如果对这方面操作不太了解的话&#xff0c;大家可以关注一下下…

linkit-smart-7688-feed 安装笔录

转载于:https://www.cnblogs.com/orangezs/p/8571791.html