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->或类作用域来强制访问类成员

  关于作者

  姓名:张坤武

 

   

时间: 2024-10-12 03:43:46

C++学习笔记 知识集锦(一)的相关文章

C学习笔记 知识集锦(二)

 1. 数组和指针 2. 字符串赋值 3. memset&memcpy 4. 机器数和真值,原码,反码和补码 5. 文件指针和文件描述符 6. 内存泄露和内存损坏 7. 什么是不可移植的程序 8. 动态库文件和静态库文件 9. make的行为 10. 库函数调用和系统调用 数组和指针 数组:同类型的数的集合 特点: 1. 数据类型一致 2. 大小固定 3. 内存空间连续 4. 数组名本质是指针常量,是该组的地址 初始化: int a [10] = {'\0'} = 0; 也可以使用循环来赋空,也

CLR via C#学习笔记----知识总概括

第1章 CLR的执行模型 托管模块的各个组成部分:PE32或PE32+头,CLR头,元数据,IL(中间语言)代码. 高级语言通常只公开了CLR的所有功能的一个子集.然而,IL汇编语言允许开发人员访问CLR的所有功能. JITCompiler函数负责将一个方法的IL代码编译成本地CPU指令.由于IL是“即时”(just in time)编译的,所以通常将CLR的这个组件称为JITter或者JIT编译器. Microsoft定义了一个“公共语言规范”(Common Language Specific

最大熵学习笔记(一)预备知识

  生活中我们经常听到人们说"不要把鸡蛋放到一个篮子里",这样可以降低风险.深究一下,这是为什么呢?其实,这里边包含了所谓的最大熵原理(The Maximum Entropy Principle).本文为一则读书笔记,将对最大熵原理以及由此导出的最大熵模型进行介绍,重点给出其中所涉及数学公式的理解和详细推导. 相关链接 最大熵学习笔记(零)目录和引言 最大熵学习笔记(一)预备知识 最大熵学习笔记(二)最大熵原理 最大熵学习笔记(三)最大熵模型 最大熵学习笔记(四)模型求解 最大熵学习笔

hadoop学习笔记——基础知识及安装

1.核心 HDFS  分布式文件系统    主从结构,一个namenoe和多个datanode, 分别对应独立的物理机器 1) NameNode是主服务器,管理文件系统的命名空间和客户端对文件的访问操作.NameNode执行文件系统的命名空间操作,比如打开关闭重命名文件或者目录等,它也负责数据块到具体DataNode的映射 2)集群中的DataNode管理存储的数据.负责处理文件系统客户端的文件读写请求,并在NameNode的统一调度下进行数据块的创建删除和复制工作. 3)NameNode是所有

IOS科研IOS开发笔记学习基础知识

这篇文章是我的IOS学习笔记,他们是知识的基础,在这里,根据记录的查询后的条款. 1,UIScrollView能完毕滚动的功能. 示比例如以下: UIScrollView *tableScrollView; tableScrollView=[[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];//窗体大小 tableScrollView.contentSize=CGSizeMake(640, 480);//设置内容视图的大

C#学习笔记(基础知识回顾)之值类型与引用类型转换(装箱和拆箱)

一:值类型和引用类型的含义参考前一篇文章 C#学习笔记(基础知识回顾)之值类型和引用类型 1.1,C#数据类型分为在栈上分配内存的值类型和在托管堆上分配内存的引用类型.如果int只不过是栈上的一个4字节的值,该如何在它上面调用方法? 二:值类型转换为引用类型--装箱 2.1CLR对值类型进行装箱时:新分配托管堆内存,将值类型的实例字段拷贝到新分配的内存中,返回托管堆中新分配对象的地址.这个地址就是一个指向对象的引用. int i = 10; Object obj = i; 三:将引用类型转换为值

[Golong]学习笔记(一) 基础知识

Go编程基础 Go的内置关键字(25个) 不多 break default func interface select case defer go map struct chan else goto package switch const fallthrough if range type continute for import return var Go的注释方法(和js一样) 单行注释: // 多行注释: /**/ Go程序一般结构 common_structure.go 通过 pack

APUE 学习笔记(一) Unix基础知识

1. Unix 体系结构 内核的接口被称为系统调用 公用函数库构建在系统调用接口之上 应用软件既可以调用公用函数库,也可以直接进行系统调用 2. 文件和目录 目录操作函数:opendir---> readdir---> closedir struct dirent 结构体 stat 系统调用 3.程序.进程.线程 程序:存放在磁盘上.并处于某个目录中的一个可执行文件.使用exec系列函数将程序从磁盘读入存储器,并使其执行 进程:程序的执行实体.进程控制的3个函数:fork.exec.waitp

&lt;&lt;Python基础教程&gt;&gt;学习笔记之|第01章|基础知识

本学习笔记主要用要记录下学习<<Python基础教程>>过程中的一些Key Point,或自己没怎么搞明白的内容,可能有点杂乱,但比较实用,查找起来也方便. 第01章:基础知识 ------ Jython:      Python的Java实现,运行在JVM中,相对稳定,但落后于Python,当前版本2.5,在TA(Python+Robot)会用到 IronPython:  Python的C#实现,运行在Common Language Runtime,速度比Python要快 >