《c++primer》之 变量和类型

2.1  基本内置类型

2.2  字面值常量

2.3  变量

     变量的类型--->决定了分配给变量的存储空间大小(含义决定大小)和可以在其上执行的操作(操作)。  

     初始化--->C++支持两种方式初始化(变量)的形式:

     (1)复制初始化:使用等号(=);

     (2)直接初始化:将初始化式放在圆括号中。

     下面来区分两个概念:初始化VS赋值

     (1)二者对于基本数据类型来说,差别不大

     初始化:指创建变量并给它赋值;

     赋值:先擦去对象的当前值,然后再复制其新的值。

     (2)然后当用于类类型对象时,二者存在效率的高低。

     初始化:指创建一个新的对象,并调相应的构造函数(直接初始化:直接调用与实参匹配的构造函数;复制初始化:总是调用复制构造函数。)。

     赋值:指讲一个对象(假设为Object1)的值代替另一个对象(Object2)的值(Object1,Object2均已存在),并调用相应的赋值操作符函数(亦可对比为:直接赋值:直接调用与实参相匹配的赋值操作符函数;复制赋值:总是调用形参为类类型的赋值操作符函数)。

  下面是它们的代码比较:以string类说明(其中m_str为类的成员变量,类型为:char* ,即字符串指针)

与实参相匹配的构造函数:
string::string(const char *str)
{
       m_str=new char[strlen(str)+1];//内存分配
       strcpy(m_str,str);//成员复制
}
复制构造函数:内存分配+成员复制
string::string(const string & s )
{
       m_str=new char[strlen(s.m_str)+1];//内存分配
       strcpy(m_str,s.m_str);//成员复制
}
总结:初始化=内存分配+成员复制

重载的赋值操作符:
string& string::string(const char* str)
{
        if(!strcmp(this->m_str,str))return *this; 
        delete [] m_str;//内存释放
        m_str=new char[strlen(str)+1];//(重新)内存分配
        stycpy(m_st,str);//成员复制
        return *this;
}

string& string::string(const string& s)
{
        if(this==&s)return *this;//防止自身赋值
        delete [] m_str;//内存释放
        m_str=new char[strlen(s.m_str)+1];//(重新)内存分配
        strcpy(m_str,s.m_str);//成员复制
        return *this;
}
总结:赋值=内存释放+(重新)内存分配+成员复制

        通过对比可以看出:初始化效率要高于赋值操作。

        故,从效率上考虑:在条件允许的情况下,最好在初始化的时候赋值,而尽量避免使用等号(“=”)。

2.3.4  变量初始化规则

       (1)内置变量自动初始化,取决于变量定义位置,如在函数体外定义的变量均初始化为0,其他函数内部则不进行自动初始化。

       (2)类类型变量的初始化,系统默认构造函数或用户自己显示定义。

2.3.5  声明和定义
注:为了让多个文件能访问想通的变量,C++区分声明和定义

        (变量)定义:为变量分配存储空间,还可为变量指定初始值。

            声明:向程序表明变量的类型和名字。另外通过使用extern关键字声明变量名而不定义它,但亦可给出变量初值,即同时定义。从这个意义上将,定义也是一种声明。

2.3.6  名字的作用域

          作用域:指程序的一段区域,用于区分名字的不同意义的上下文。有:全局作用域(main函数外部),局部作用域,语句作用域。

2.3.7  在变量使用处定义变量

           即在对象第一次被使用的地方定义对象,可提高程序的可读性。

2.4  const 限定符

          (1)定义const对象

            const限定符:把一个对象转换成一个常量,由于常量在定以后即不能修改,故定义时必须初始化

          (2)const对象默认为文件的局部变量

            之所以这样定义语法, 原因在于:C++允许const变量定义在头文件中。

           问题1:先分析为什么允许const变量定义在头文件中:

            答:一般,常量表达式是编译器在编译时就能计算出结果的表达式。所以const变量成为常量表达式后,编译器就要知其初始化时式(明显:这是全局变量所不能提供的)。根据编译器的按文件编译原则,同时为了能够让多个文件使用相同的常量值,const变量和它的初始化式必须是每个文件都可见的。所以,把一些这样的const变量定义在头文件中,此时,无论该const变量何时使用,编译器都能看见其初始化式。

            问题2:const对象为什么默认为文件的局部变量

            答:即,现已知C++变量可定义在头文件中,而头文件一般可被多个源文件包含,所以每个包含该头文件的源文件都会有自己的const变量,其名称和值都一样。但是由于C++中的全局变量只能定义一次,否则链接时会出现变量重定义错误,所以const对象默认为文件的局部变量。

虽然全局作用域声明的const变量是单个文件作用域,不能在其他文件中使用,但是通过在定义时前面用extern加以修饰,则可消除const文件作用域,就可以在整个程序中访问const对象。

2.5  引用

          定义:是一种复合类型,即指需要其他类型定义的类型。

          在引用的情况下,每一种引用类型都”关联到“一其他类型,且引用必须用与该引用同类型的对象进行初始化(初始化,指明引用关联哪个对象的唯一方法)。

        (1)引用是别名。

        (2)定义多个引用

        (3)const引用:即指向const对象的引用。

            I、非const引用:即普通引用,只能绑定到与该引用同类型的对象。

            II、const引用:可以绑定到不同但相关的类型的对象或绑定到右值。

to  be continued......

2.6  typedef 名字----------定义类型同义词

         typedef通常用于三种目的:1.隐藏实现:隐藏特定类型 的实现,强调使用类型的目的;2.化繁为简:简化复杂的类型定义,使其更易于理解;3.明确目的:允许一种类型用于多个目的,同时使得每次使用该类型的目的明确

2.7  枚举 ---------不但定义整数常量集(第一个成员默认为0,当然亦可自定义,往后自增1),而且聚集成组。

    (1) 定义和初始化枚举--------关键字:enum

    (2)枚举成员是常量--------即不能改变枚举成员的值

    (3) 每个enum都定义一种唯一的类型-------即只能与同类型对象“交流”

2.8  类类型

      C++中通过定义类类型来自定义数据类型

     (1)从操作开始设计类---------先考虑操作,再考虑数据

      每个类都定义了一个接口和一个实现。通常,先定义该类的接口,即该类所提供的操作。通过这些操作,可决定该完成其功能所需要数据,以及是否需要定义一些函数来支持该类实现。接口:由使用该类的代码需要执行的操作组成; 实现:一般包括该类所需的数据

    (2)定义Sale_item类

    (3)类的数据成员

       定义变量与定义数据成员区别:

       一般不能把类成员的初始化作为其定义的一部分。因为类不是在类里面 定义数据成员初始化数据成员,而是通过构造函数进行初始化。

    (4)访问标号-------控制使用该类的代码(在类外)是否可以使用给定的成员

    (5)使用关键字struct

      用class和struct关键字定义类的唯一差别在于默认访问级别:默认情况下,struct的成员为public,而class的成员为private。

2.9  编写自己的头文件

       注:一般类定义都会放在头文件中。

       由多个文件组成的程序需要一种方法连接名字的使用和声明,在C++中,这是通过头文件实现的。1.为了允许吧程序分成独立的逻辑块,C++支持分别编译;2.为了减少处理头文件的编译时间,有些C++的实现支持预编译(头文件)。

注:预编译又称预处理,做一些代码文本的替换工作。主要处理以#开头的预处理指令。

2.9.1  设计自己的头文件  

       头文件一般包含:类的定义、extern变量的声明以及函数的声明。

       好处:1.保证所有文件使用给定实体的同一声明(即共享);2.当声明需要修改时,只需更新头文件。

注:头文件中所做的声明在逻辑上应该是适于放在一起的。编译头文件需要一定的时间,若头文件过大,程序员可能不愿承受包含该头文件所带来的编译代价------->预编译。

      (1)头文件用于声明而不是定义

        由于头文件包含在多个原文件中,故不应该含有变量或函数的定义。但是对于头文件不应含有定义有三个例外:1.可以定;2.可定义值在编译时就应知的const对象;3.可定义incline函数。(这些均源于编译器需要更多的解释信息

注:通常,头文件中应该只定义确实必要的东西。

        (2)一些const对象定义在头文件中

         由于const对象默认为文件的局部变量,而当我们在头文件中定义了const变量后,每个包含该头文件的源文件都有了自己的const变量,其名和值都一样。1.当该const变量是常量表达式初始化时,可保证所有的变量都有相同的值。但在实践中大部分编译器在编译时,都会用相应的常量表达式替换const变量的使用,故实践中,不会有任何存储空间用于存储常量表达式初始化的const变量。2.当const变量不是用常量表达式初始化时,那么它就不应该在头文件定而是和其他的变量一样,该const变量应在一个源文件中定义并初始化。应在头文件为它添加extern声明,以便多个文件共享。

2.9.2  预处理器的简单介绍

           预处理器:用指定的头文件内容替代每个#include.

          (1)头文件经常需要其他文件

          (2)避免多重包含--------->预处理器变量

            为了避免名字冲突,预处理器变量经常用全大写字母表示。

            #define:接受一个名字,并定义该名字为预处理器变量

            #ifndef:检测指定的预处理器是否未定义,并以#endif结束

           (3)使用自定义的头文件


      

  



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值