C++学习笔记 知识集锦(一)
1.内存管理的开销 2.函数调用框架 3.类为什么要定义在头文件 4.C++的组合 5.在类的外部定义成员函数 6.bool类型为什么可以当做int类型 7.无符号保留原则
8.C++类型检查 9.何时会发生隐式类型转换 10函数的返回值 11.浅拷贝 12.对数组无效的指引 13.cout的使用 14.文件的读写 15.名字查找
内存管理的开销
当在栈里自动创建对象时,对象的大小和它们的生存期被准确地内置在生成的代码里,这是因为编译器知道确切的类型,数量和范围,而在堆里创建对象还包括另外的时间和空间的开销,例如使用new创建
对象,此时会调用malloc来从堆里申请一块内存,从堆里搜索一块足够大的内存来满足请求,这可以通过检查某种方式排列的映射或目录来实现,这样的映射或目录用以显示内存的使用情况,这个过程很快
但也可能要试探几次,所以它可能是不确定的,即每次运行malloc并不是花费了完全相同的时间,在指向这块内存的指针返回之前,这块内存的大小和地址必须记录下来,这样以后再调用malloc就不会使用它
而且当free时系统就会知道释放多大的内存,类stash和stack自己都将不“拥有”它们指向的对象,即当stash和stack对象出了范围,它也不会为它指向的对象调用delete,视图使它们成为普通的类是不可能的,
原因是它们是void指针,而如果delete一个void指针,唯一发生的事情就是释放内存,这是因为既没有类型信息也没有办法使得编译器知道要调用哪个析构函数
函数调用框架
当编译器为函数调用产生代码时,它首先把所有的参数压栈,然后调用函数,在函数内部产生代码,向下移动指针为函数局部变量提供存储单元(这里的向下是相对的,在压栈时,机器的栈指针可能增加也可能
减少),但是在汇编语言CALL中,CPU把程序代码中的函数调用指令的地址压栈,所以汇编语言RETURN可以使用这个地址返回到调用点,函数使用的这块内存为函数框架,有函数参数,返回地址,局部变量
类为什么要定义在头文件
类可以在函数体内定义,但是因为这样的类受到了一些限制,所以类一般都不定义在函数体内,在函数体外定义类时,在各个知道的源文件中可能只有一处该类的定义,而且如果要在不同的文件中使用同一
个类,类的定义就必须保持一致,为了确保各个文件中的类定义一致,类通常定义在头文件中,而且类所在头文件的名字应与类的名字一样
C++的组合
简单地在新类中创建已存在类的对象,因为新类是由已存在的对象组合而成,所以这种方法称为组合。
在类的外部定义成员函数
在类的外部定义成员函数时函数的定义必须与声明匹配,也就是说返回类型,参数列表,函数名都得与类内的声明保持一致,如果成员函数被声明为常量成员函数,
那么它的定义也必须在参数列表后面明确指定const,类外部定义的成员名字必须包含类名,const一般位于声明或定义的最后
bool withline() const ;// 声明
bool CC_ListAll_T1M1_L::withline()const {} //定义,若是有引用,那么应该将&放在类名之前,返回类型之后,如bool &CC_ListAll_T1M1_L::withline() const {}
bool类型为什么可以当做int整型
实际上bool型变量占用了一个字节的内存,当值为false的时候,实际存储的是0x00,为true时实际存储的是0x01,因此可以作为int整型使用
bool型只分0与非0,0为false,其余的包括负数在内都是true
无符号保留原则
当一个无符号类型与int或更小的整型混合使用时,结果类型是无符号类型,有时可能导致负数丢失符号位,所以避免使用无符号类型(除非必要),以免增加不必要的复杂性,
尤其是不要仅仅因为无符号不存在负值(如年龄,国债等)而用它来表示数量
C++类型检查
与大多数语言一样,C++也是类型决定了能对该对象进行的操作,一条表达式是否合法依赖于其中参与运算的对象的类型,C++是一种静态数据类型语言,它的类型检查发生在编译时,
因此编译器知道程序中每一个变量对应的数据类型,C++定义了几种基本内置类型,如字符,整型,浮点数等,同时也为程序员提供了自定义数据类型的机制
何时会发生隐式类型转换
在大多数表达式中,比int类型小的整型值首先提升为较大的整数类型,
在条件中,非bool值转化为bool值
初始化过程中,初始值转换成变量的类型,在赋值语句中,右侧运算对象转换成左侧运算对象的类型
如果算术关系或运算关系的对象有多种类型,需要换换成同一种类型,函数调用也会发生类型转换
函数返回值
对于无返回值函数,那么在其语句的结尾可以没有显式的return语句,因为在最后一句会隐式的执行return;
对于有返回值函数,那么函数必须保证返回一个与函数类型一致的值,或者可以隐式转换成函数类型的,否则编译器将报错
返回一个值的方式和初始化一个值的方式完全一样,返回的值用于初始化调用点的一个临时变量,该临时变量就是函数调用的结果
浅拷贝
只是将变量内容拷贝给新的指针,但是资源没有拷贝给变量,因此拷贝之后这些变量指向的是同一个内存地址,那么当其中的一个变量销毁并且将其所指向资源进行销毁后,其后它的几个拷贝变量在
销毁时则无法回收资源,产生问题
对数组无效的指引
char name[] = "darla";char c = name [10];//对一个数组无效的指引将导致不明确行为,结果是不可预期的,此例中没有name[10]
返回数组指针
因为数组不能被拷贝,所以函数不能返回数组,不过,函数可以返回数组的指针或引用,返回一个数组指针还是比较繁琐的,最直接的就是使用类型别名
例子:typedef int arrT[10]; //arrT是一个类型别名,它表示的类型是含有10个整数的数组
using arrT = int [10]; //arrT的等价声明
之后就可以arrT*func(int i); //此时func返回一个指向含有10个整数的数组的指针
比如在主函数中定义了几个数组,int a[] = {1,2,3,4,5},int b[] = {6,7,8,9,10};那么就可以在小函数的末尾使用return &a;或者return &b;
cout的使用
通常与<<结合,cout<< 通过<<操作符把一系列的参数传递给cout对象,然后cout对象按从左到右的顺序把参数打印出来,<<本来是向左移位,但是C++允许操作符重载,
和iostream对象在一起,操作符<<意思就是发送到,例子如下:
cout <<dec<<15<<endl; 表示把数字以十进制打出来,数据本来放在缓冲区,通过endl可以使数据从缓冲区输出,否则就是等待缓冲区满才输出,dec表示是十进制,oct是八进制,hex是十六进制
cin>>a>>b;输入a,b的值,cout可以重定向到文件里,cerr只能输出在显示器上,cerr不经过缓冲区,直接向显示器输出信息,clog默认数据是经过缓冲的
文件的读写
包含<fstream>,如果打算使用cin,cout,那么最好也显示包含<iostream>,尽管<fstream>会自动包含<iostream>,在<iostream>库中的getline()
例子: #include<string> #include<iostream> #include<fstream>
int main(){
ifstream in("FillString.cpp");
string s,line; //string 具有动态性,不必担心string的内存分配,会自动扩展以保存新的输入
while(getline(in, line)); //getline()每次从文件中取一行,string类有许多函数可以对字符串进行查找和操作
s += line + "\n";
cout <<s;
}
名字查找
定义:寻找与所用名字最匹配的声明的过程
1. 首先,在名字所在的块中寻找其他声明语句,只考虑在名字的使用之前出现的声明(确认是否是局部变量)
2. 如果没找到,继续查找外围作用域,继续向其他地方扩散寻找,确认是否是全局变量
3. 如果最后还是没有找到,那么程序会报错
对于定义在类内部的成员函数来说,解析规则有所区别, (1) 首先,编译成员的声明 (2) 直到类全部可见后才编译函数体。 按照这种两阶段的方式处理类可以简化类代码的组织方式,因为成员函数体
直到整个类可见后才会被处理,所以它能使用类中定义的所有名字,相反,如果函数的定义和成员的声明被同时处理,那么我们将不得不在成员函数中只使用那些已经出现的名字,
这种两阶段的处理方式只适用于成员函数中使用的名字,声明中使用的名字,包括返回类型或者参数列表中使用的名字,都必须在使用前确保可见,如果某个成员的声明
使用了类中尚未出现的名字,则编译器将会在定义该类的作用域继续查找
例子:typedef double Money; //当编译器看到balance函数的声明语句时,它将在Account类的范围内寻找对Money的声明,编译器只考虑Account中在使用Money前出现的声明,
string bal; //所以在private中定义的是无效的,因为没找到匹配的成员,所以编译器会在Account的外层继续查找,在这个例子中,编译器会找到typedef声明的Money
class Account { //该类型被作为balance函数的返回类型以及数据成员bal的类型,另一方面,balance函数体在整个类可见后才被处理,因此,该函数的return语句
public: //返回名为bal的成员而非外层作用域的string对象
Money balance(){return bal;}
private:
Money bal;
}
类型名要特殊处理:一般内层作用域可以重新定义外层作用域中的名字,即使该名字已经在内层作用域中使用过,然而在类中如果成员使用了外层作用域中的某个名字,而该名字代表一种数据类型,
则类不能在之后重新定义该名字,尽管重新定义的类型与外层定义的类型完全一致也不行,
函数的参数列表中的变量最好不要与类成员变量重名,当重名之后如果想使用类成员变量,那么可以通过this->或类作用域来强制访问类成员
关于作者
姓名:张坤武
邮箱:1498462303@qq.com
C++学习笔记 知识集锦(一)的更多相关文章
- C++学习笔记 知识集锦(二)
1. 命名规范 2. 代码格式 3. QString的判断 4. 对象的判空 5. 隐式接口&显式接口 6. vector&string 7. static 8. const 9. v ...
- C学习笔记 知识集锦(二)
1. 数组和指针 2. 字符串赋值 3. memset&memcpy 4. 机器数和真值,原码,反码和补码 5. 文件指针和文件描述符 6. 内存泄露和内存损坏 7. 什么是不可移植的程序 ...
- C学习笔记 知识集锦(一)
1.标识符 2.寄存器变量 3.全局变量 4.分配内存与初始化 5.变量定义与声明 6.作用域规则 跳转语句 7.&与&&,|和||的意义与区别 8.如何选择switch c ...
- (转) OpenCV学习笔记大集锦 与 图像视觉博客资源2之MIT斯坦福CMU
首页 视界智尚 算法技术 每日技术 来打我呀 注册 OpenCV学习笔记大集锦 整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的 ...
- paper 93:OpenCV学习笔记大集锦
整理了我所了解的有关OpenCV的学习笔记.原理分析.使用例程等相关的博文.排序不分先后,随机整理的.如果有好的资源,也欢迎介绍和分享. 1:OpenCV学习笔记 作者:CSDN数量:55篇博文网址: ...
- CLR via C#学习笔记----知识总概括
第1章 CLR的执行模型 托管模块的各个组成部分:PE32或PE32+头,CLR头,元数据,IL(中间语言)代码. 高级语言通常只公开了CLR的所有功能的一个子集.然而,IL汇编语言允许开发人员访问C ...
- jQuery学习笔记 - 基础知识扫盲入门篇
jQuery学习笔记 - 基础知识扫盲入门篇 2013-06-16 18:42 by 全新时代, 11 阅读, 0 评论, 收藏, 编辑 1.为什么要使用jQuery? 提供了强大的功能函数解决浏览器 ...
- 20145330《Java学习笔记》第一章课后练习8知识总结以及IDEA初次尝试
20145330<Java学习笔记>第一章课后练习8知识总结以及IDEA初次尝试 题目: 如果C:\workspace\Hello\src中有Main.java如下: package cc ...
- Nodejs学习笔记(六)--- Node.js + Express 构建网站预备知识
目录 前言 新建express项目并自定义路由规则 如何提取页面中的公共部分? 如何提交表单并接收参数? GET 方式 POST 方式 如何字符串加密? 如何使用session? 如何使用cookie ...
随机推荐
- ytu 1057: 输入两个整数,求他们相除的余数(带参的宏 + 模板函数 练习)
1057: 输入两个整数,求他们相除的余数 Time Limit: 1 Sec Memory Limit: 128 MBSubmit: 177 Solved: 136[Submit][Status ...
- Java基础知识点3:集合类
集合类是Java编程中经常会用到的一类常用类库,在这里将会对整个集合类进行介绍: Collection接口: Collection接口是所有集合类的根接口,代表了所有含有多个元素的集合,无论这个集合中 ...
- php实现数据库数据读取生成缓存文件
有些时候我们希望减少对数据库的 查询来提高程序的性能,因为这些数据不是经常变更的,而是会在很长一段时间内都不会变化,因此,我们每连接一次数据库,都会把相应的结果用文件的形式保存 起来.比如对于一个商城 ...
- nodejs review-02
30 Receive POST data POST接受JSON数据处理; //req. res都是可读的stream; http.createServer(function (req, res) { ...
- windows查看端口占用情况
1,查看指定端口被哪个进程占用. >netstat -ano|findstr 8008 TCP 127.0.0.1:8083 0.0.0.0:0 ...
- AngularJs表单验证
常用的表单验证指令 1. 必填项验证 某个表单输入是否已填写,只要在输入字段元素上添加HTML5标记required即可: <input type="text" requir ...
- 2014亚马逊在线笔试题目及解决方案(MMChess问题)
整体思路:关键是需要知道当前Steps数组中的全排列即可,而且需要不重复的全排列.即关键在于非递归的全排列实现即可~ 其实直接利用STL中的next_permutation算法的,这里我又自己实现了一 ...
- Leetcode N-Queens II
Follow up for N-Queens problem. Now, instead outputting board configurations, return the total numbe ...
- [ACM训练] 数据结构----树、二叉树----c++ && python
树结构,尤其是二叉树结构是算法中常遇见的,这里根据学习过程做一个总结. 二叉树所涉及到的知识点有:满二叉树与完全二叉树.节点数目的关系.节点数与二叉树高度的关系.层次遍历.深度优先遍历.广度优先遍历等 ...
- Javascript for循环指定锚点跳转
在某些使用多层嵌套for循环的场合里 会用到break和continue来中途跳转循环 break是跳出整个循环 continue是跳出当前循环,继续下次循环 而多层for循环嵌套里使用这两个关键字默 ...