`
clskkk2222
  • 浏览: 33999 次
  • 性别: Icon_minigender_1
  • 来自: 南京
社区版块
存档分类
最新评论
  • NeuronR: 引用因为用于向函数传递对象和从函数返回对象,该构造函数一般不应 ...
    复制构造函数

变量和基本类型

    博客分类:
  • C++
阅读更多

类型是所有程序的基础,类型告诉我们数据代表什么意思以及可以对数据执行哪些操作。
类型确定了数据和操作在程序中的意义。

 

基本内置类型
C++ 定义了一组表示整数、浮点数、单个字符和布尔值的算术类型,另外还定义了一种称为 void 的特殊类型。

算术类型的存储空间依机器而定,单位:位(bit)

C++标准规定了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间。

可以用sizeof()查看
//括号中可以是类型,变量,常量甚至字面量,本质应该是类型,是对类型的判断,意为:显示类型需要的内存空间大小,单位:字节

 

#include <iostream>
using namespace std;

int main()
{
	cout << "bool:" << sizeof(bool) << endl;
	cout << "char:" << sizeof(char) << endl;
	cout << "short:" << sizeof(short) << endl;
	cout << "int:" << sizeof(int) << endl;
	cout << "long:" << sizeof(long) << endl;
	cout << "float:" << sizeof(float) << endl;
	cout << "double:" << sizeof(double) << endl;
	cout << "long double:" << sizeof(long double) << endl;
	cout << "字符串:" << sizeof("字符串") << endl;
	
	return 0;
}

 

Integral Types

表示整数、字符和布尔值的算术类型合称为整型

字符类型有两种:char 和 wchar_t。
字符型char 用ascii码表示,共有128个标准字符(0~127)。 
常用的一些asc码:a-97(十进制)-0x61(十六进制) ,
                  A-65-0x41 ,    z-122-0x7A , Z-90-0x5A ,
                   0(零)-48-0x30 , 9-57-0x39 , \0-0  , 
                   "空格"-32-0x20 , '\t'-9 ,'\n'-10 , '\r'-13-0xD
                  
char 类型通常是单个机器字节(byte),wchar_t 类型用于扩展字符集,比如汉字和日语

#include <iostream>
using namespace std;

int main()
{
    char c = 'a';
    wchar_t w = 'a';
    cout  << c << "	" << (int)c << endl;
    cout << "sizeof(char)=" << sizeof(char) << endl;
    cout <<  w << "	" << (int)w << endl;
    cout << "sizeof(wchar_t)=" << sizeof(wchar_t) << endl;
    
    return 0;
}

short、int 和 long 类型都表示整型值

bool 类型表示真值 true 和 false。可以将算术类型的任何值赋给 bool 对象。
0 值算术类型代表 false,任何非 0 的值都代表 true。
bool类型的输出默认是0或1 ,在输出定向语句前写上<<boolalpha<<"变量名"则输出 true或者false;输入同理;

#include <iostream>
using namespace std;

int main()
{
	bool b=true;
	cout << "b=" << b << endl;
	b = false;
	cout << "b=" << b << endl;
	b = -3.14;
	cout << "b=" << boolalpha << b << endl;
}

除 bool 类型外,整型可以是带符号的(signed)也可以是无符号的(unsigned)。

整型 int、short 和 long 都默认为带符号型。

和其他整型不同,char 有三种不同的类型:plain char 、unsigned char 和 signed char。虽然 char 有三种不同的类型,但只有两种表示方式。可以使用 unsigned char 或 signed char 表示 char 类型。使用哪种 char 表示方式由编译器而定。

无符号型中,所有的位都表示数值。
C++ 标准并未定义 signed 类型如何用位来表示,而是由每个编译器自由决定如何表示 signed 类型。

整型的赋值

对象的类型决定对象的取值。当我们试着把一个超出其取值范围的值赋给一个指定类型的对象时,结果取决于这种类型是 signed 还是 unsigned 的。

对于 unsigned 类型来说,编译器必须调整越界值使其满足要求。编译器会将该值对 unsigned 类型的可能取值数目求模,然后取所得值。

C++ 中,把负值赋给 unsigned 对象是完全合法的,其结果是该负数对该类型的取值个数求模后的值。

当将超过取值范围的值赋给 signed 类型时,由编译器决定实际赋的值。

#include <iostream>
using namespace std;

int main()
{
    unsigned char c1 = 336;
    unsigned char c2 = -80;
    cout << (int)c1 << endl;
    cout << (int)c2 << endl;
    
    return 0;
}

 Floating-Point Types

类型 float、 double 和 long double 分别表示单精度浮点数、双精度浮点数和扩展精度浮点数。

Note:对于实际的程序来说,float 类型精度通常是不够的——float 型只能保证 6 位有效数字,而 double 型至少可以保证 10 位有效数字,能满足大多数计算的需要。

Suggestion:当执行整型算术运算时,很少使用 short 类型。大多数程序中,使用 short 类型可能会隐含赋值越界的错误。同样的道理,虽然 char 类型是整型,但是 char 类型通常用来存储字符而不用于计算。在大多数机器上,使用 int 类型进行整型计算不易出错。选择类型前要先了解程序的细节并且比较 long 类型与 int 类型的实际运行时性能代价。使用 double 类型基本上不会有错。在 float 类型中隐式的精度损失是不能忽视的,而 double 类型精度代价相对于 float 类型精度代价可以忽略。(事实上,有些机器上,double 类型比 float 类型的计算要快得多。)long double 类型提供的精度通常没有必要,而且还需要承担额外的运行代价。

字面值常量
每个字面值都有相应的类型,例如:0 是 int 型,3.14159 是 double 型。只有内置类型存在字面值,没有类类型的字面值,也没有任何标准库类型的字面值。

整型字面值规则
定义字面值整数常量可以使用以下三种进制中的任一种:十进制、八进制和十六进制。
以 0(零)开头的字面值整数常量表示八进制,以 0x 或 0X 开头的表示十六进制。
    
字面值整数常量的类型默认为 int 或 long 类型。

通过在数值后面加 L 或者 l(字母“l”大写或小写)指定常量为 long 类型。
定义长整型时,应该使用大写字母 L。小写字母 l 很容易和数值 1 混淆。

类似地,可通过在数值后面加 U 或 u 定义 unsigned 类型。同时加 L 和 U 就能够得到 unsigned long 类型的字面值常量。但其后缀不能有空格

没有 short 类型的字面值常量。

通常可以用十进制或者科学计数法来表示浮点字面值常量。使用科学计数法时,指数用 E 或者 e 表示。默认的浮点字面值常量为 double 类型。在数值的后面加上 F 或 f 表示单精度。同样加上 L 或者 l 表示扩展精度
    
布尔字面值和字符字面值
单词 true 和 false 是布尔型的字面值
可打印的字符型字面值通常用一对单引号来定义

在字符字面值前加 L 就能够得到 wchar_t 类型的宽字符字面值

非打印字符的转义序列
换行符 \n
报警(响铃)符 \a
反斜线 \\
单引号 \'
双引号 \"

我们可以将任何字符表示为以下形式的通用转义字符:
     \ooo
这里 ooo 表示三个八进制数字,这三个数字表示字符的数字值。
字符’\0’通常表示“空字符(null character)”,
同样也可以用十六进制转义字符来定义字符:
     \xddd

字符串字面值
字符串字面值常量用双引号括起来的零个或者多个字符表示,不可打印字符表示成相应的转义字符

为了兼容 C 语言,C++ 中所有的字符串字面值都由编译器自动在末尾添加一个空字符。

宽字符串字面值,一样在前面加“L”,如

宽字符串字面值是一串常量宽字符,同样以一个宽空字符结束。

两个相邻的仅由空格、制表符或换行符分开的字符串字面值(或宽字符串字面值),可连接成一个新字符串字面值。

在一行的末尾加一反斜线符号可将此行和下一行当作同一行处理。
注意反斜线符号必须是该行的尾字符——不允许有注释或空格符。同样,后继行行首的任何空格和制表符都是字符串字面值的一部分。正因如此,长字符串字面值的后继行才不会有正常的缩进。

#include <iostream>
using namespace std;

int main()
{
    cout << 20 << endl;   // decimal
    cout << 024 << endl;  // octal
    cout << 0x14 << endl; // hexadecimal
    
    cout << 128u << endl;    // unsigned         
    cout << 1024UL << endl;  // unsigned long
    cout << 1L << endl;      // long       
    cout << 8Lu << endl;     // unsigned long 
    
    cout << 3.14159F << "  " << 3.14159E0f << endl;
    cout << .001f << "  " << 1E-3F << endl; 
    cout << 12.345L << "  " << 1.2345E1L << endl; 
    cout << 0. << "  " << 0e0 << endl;
    
    cout << true << endl;
    cout << false << endl;
    
    cout << 'a' << endl;
    cout << L'a' << endl;
    
    cout << "\n" ;
    cout << "\a" << endl; //bell
    cout << "\'" << endl;
    cout << "\"" << endl;
    cout << "\\" << endl;
    
    cout << "abc" << endl;
    cout << sizeof("abc") << endl;
    
    cout << L"abc" << endl;
    cout << sizeof(L"abc") << endl;
    
    // concatenated long string literal
    cout << "a multi-line "
             "string literal "
             "using concatenation"
          << endl;
          
    // multiline string literal
    cou\
t << "a multi-line \
string literal \
using a backslash" << en\
dl;

    return 0;
}

 变量,提供了程序可以操作的有名字的存储区


在 C++ 中,操作是否合法是在编译时检查的。

C++ 是强类型语言,每一个变量都有明确的类型(先声明后使用),且保持不变。

左值和右值
左值可以出现在赋值语句的左边或右边
右值只能出现在赋值的右边,不能出现在赋值语句的左边。

左值:变量本身,赋值表达式的返回值,++i
右值:非左值


变量名,即变量的标识符,可以由字母、数字和下划线组成。变量名必须以字母或下划线开头,并且区分大小写字母:C++ 中的标识符都是大小写敏感的。

C++ 保留了一组词用作该语言的关键字。关键字不能用作程序的标识符

变量命名习惯
变量名一般用小写字母
标识符应使用能帮助记忆的名字,见名知意
包含多个词的标识符书写为在每个词之间添加一个下划线,或者每个内嵌的词的第一个字母都大写
第一个字符必须是字母或下划线,
只能使用字母、数字、下划线,
中间不能有空格,
不能是保留字,不能与全局函数和数据类型同名;
严格区分大小写,使用易懂的变量名;
长度一般不要超过32个字符,一般在15个以内;

命名习惯最重要的是保持一致。

定义对象
每个定义都是以类型说明符开始,后面紧跟着以逗号分开的含有一个或多个说明符的列表,分号结束定义。
。类型决定了分配给变量的存储空间的大小和可以在其上执行的操作。

定义时指定了初始值的对象被称为是已初始化的。C++ 支持两种初始化变量的形式:复制初始化和直接初始化。复制初始化语法用等号(=),直接初始化则是把初始化式放在括号中:

Note:初始化不是赋值!
初始化指创建变量并给它赋初始值,而赋值则是擦除对象的当前值并用新值代替。
直接初始化语法更灵活且效率更高

可以用同一个定义中前面已定义变量的值初始化后面的变量。
已初始化变量和未初始化变量可以在同一个定义中定义。

变量初始化规则
内置类型变量的初始化
内置类型变量是否自动初始化取决于变量定义的位置。在函数体外定义的变量都初始化成 0,在函数体里定义的内置类型变量不进行自动初始化。

建议每个内置类型的对象都要初始化。虽然这样做并不总是必需的,但是会更加容易和安全,除非你确定忽略初始化式不会带来风险。

#include <iostream>
using namespace std;

int iglobal;  
int main()
{
    int ilocal ;
    cout << "iglobal = " << iglobal << endl;
    cout << "ilocal = " << ilocal << endl;
    
    
    //cout << "a=" << a << endl;  ERROR!!! no declaration
	int a, b=10, c = b,d;   //ok,but bad style

	cout << "b=" << b << endl;
	cout << "c=" << c << endl;
	cout << "d=" << d << endl;  //random number uninitialize
 
    cout << "a=" << a << endl;  //random number uninitialize
    a = 100;                    //assign 100 to a
    cout << "a=" << a << endl;
   
    	
    int i1(1024);     // direct-initialization
    int i2 = 1024;    // copy-initialization
    cout << "i1=" << i1 << endl;
    cout << "i2=" << i2 << endl;
	
    return 0;
}

 每个类都定义了该类型的对象可以怎样初始化。


声明和定义
变量的定义用于为变量分配存储空间,还可以为变量指定初始值。在一个程序中,变量有且仅有一个定义。

声明用于向程序表明变量的类型和名字。定义也是声明:当定义变量时我们声明了它的类型和名字。可以通过使用extern关键字声明变量名而不定义它。不定义变量的声明包括对象名、对象类型和对象类型前的关键字extern:


extern 声明不是定义,也不分配存储空间。
程序中变量可以声明多次,但只能定义一次。

如果声明有初始化式,那么它可被当作是定义,即使声明标记为 extern:

只有当 extern 声明位于函数外部时,才可以含有初始化式。

在 C++ 语言中,变量必须且仅能定义一次,而且在使用变量之前必须定义或声明变量。

名字的作用域
C++ 语言中,大多数作用域是用花括号来界定的。一般来说,名字从其声明点开始直到其声明所在的作用域结束处都是可见的。
定义在所有函数外部的名字具有全局作用域,可以在程序中的任何地方访问。

C++ 中作用域可嵌套

局部变量最好使用不同的名字。

通常把一个对象定义在它首次使用的地方是一个很好的办法。

#include <iostream>
using namespace std;

/**
 *global Variable,can be used in this file, 
 *or other files in this way ↓ 
 *extern int iglobal;
 */
int iglobal = 2; 

void print()
{
    int j = 3;
	cout << "j=" << j << endl;  //local Variable,can only be used in the {}
    cout << iglobal << endl;     
}

extern double pi = 3.1416; //ok, definition because pi has a initializer 

int main()
{   
    //extern declaration may include an initializer 
    //only if it appears outside a function
    //extern double pi = 3.1416; ERROR! 
    
    //extern int i;  declares but does not define i,i must be in the other file
    
    int i;          //  declares and defines i
    
    cout << iglobal << endl;
    cout << "oh ,I can't see j" << endl;
    
    cout << "=========print()=========" << endl;
    print();
    cout << "=========print()=========" << endl;
	
    return 0;
}

 

const 限定符

它把一个对象转换成一个常量,因为常量在定义后就不能被修改,所以定义时必须初始化。

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

在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。

除非特别说明,在全局作用域声明的 const 变量是定义该对象的文件的局部变量。此变量只存在于那个文件中,不能被其他文件访问。

通过指定 const 变更为 extern,就可以在整个程序中访问 const 对象

非 const 变量默认为 extern。要使 const 变量能够在其他的文件中访问,必须地指定它为 extern。

References
引用就是对象的另一个名字。在实际程序中,引用主要用作函数的形式参数
引用是一种复合类型,通过在变量名前添加“&”符号来定义。

引用必须用与该引用同类型的对象初始化:


引用是别名,作用在引用上的所有操作事实上都是作用在该引用绑定的对象上

当引用初始化后,只要该引用存在,它就保持绑定到初始化时指向的对象。不可能将引用绑定到另一个对象。

可以在一个类型定义行中定义多个引用。必须在每个引用标识符前添加“&”符号

const 引用是指向 const 对象的引用
需要规定将普通的引用绑定到 const 对象是不合法的。

const 引用可以初始化为不同类型的对象或者初始化为右值,如字面值常量:

非 const 引用只能绑定到与该引用同类型的对象。
const 引用则可以绑定到不同但相关的类型的对象或绑定到右值。

#include <iostream>
using namespace std;

const int count1 = 10;  //can be only used in this file!

extern const int count2 = 20;  //can be used in other files!

int main()
{   
    //const int i ;      ERROR! uninitialized const `i' 
    const int i = 1;
    //i = 2;            ERROR! assignment of read-only variable `i' 
    
    int ival = 1024;
    int &refVal = ival; // ok: refVal refers to ival
    //int &refVal2;       error: a reference must be initialized
    //int &refVal3 = 10;    error: initializer must be an object
    
    int i = 42;
    //  legal for const references only
    const int &r = 42;
    const int &r2 = r + i;
 	
    return 0;
}

 

 

Typedef
typedef 可以用来定义类型的同义词

typedef 名字可以用作类型说明符:

typedef 定义以关键字 typedef 开始,后面是数据类型和标识符。标识符或类型名并没有引入新的类型,而只是现有数据类型的同义词。typedef 名字可出现在程序中类型名可出现的任何位置。

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

Enumerations

枚举的定义包括关键字 enum,其后是一个可选的枚举类型名,和一个用花括号括起来、用逗号分开的枚举成员列表。

默认地,第一个枚举成员赋值为 0,后面的每个枚举成员赋的值比前面的大 1。

可以为一个或多个枚举成员提供初始值,用来初始化枚举成员的值必须是一个常量表达式。
(常量表达式是编译器在编译时就能够计算出结果的整型表达式)

不能改变枚举成员的值。枚举成员本身就是一个常量表达式,所以也可用于需要常量表达式的任何地方

每个 enum 都定义一种唯一的类型
枚举类型的对象的初始化或赋值,只能通过其枚举成员或同一枚举类型的其他对象来进行

枚举成员的取值可以重复

#include <iostream>
using namespace std;

typedef double wages;       //  wages is a synonym for double
typedef int exam_score;     //  exam_score is a synonym for int

enum Color{RED, GREEN=3, BLUE=3, WHITE, BLACK=255};

int main()
{   
    wages salary = 2100.00;         // double hourly, weekly;
    exam_score test_result = 100;   // int test_result;
    
    cout << salary << endl;
    cout << test_result << endl;
    
    
    cout << "RED=" << RED << endl;
    cout << "GREEN=" << GREEN << endl;
    cout << "WHITE=" << WHITE << endl;
    cout << "BLACK=" << BLACK << endl;
    
    //Color YELLOW = 5;  ERROE! invalid conversion from `int' to `Color' 
    Color YELLOW = WHITE; //ok
 	
    return 0;
}

 

Class

类定义以关键字 class 开始,其后是该类的名字标识符。类体位于花括号里面。花括号后面必须要跟一个分号。

类体可以为空。类体定义了组成该类型的数据和操作。这些操作和数据是类的一部分,也称为类的成员。操作称为成员函数,而数据则称为数据成员。

定义变量和定义数据成员存在非常重要的区别:一般不能把类成员的初始化作为其定义的一部分。当定义数据成员时,只能指定该数据成员的名字和类型。类不是在类定义里定义数据成员时初始化数据成员,而是通过称为构造函数的特殊成员函数控制初始化。

访问标号 public、private 可以多次出现在类定义中。给定的访问标号应用到下一个访问标号出现时为止。

struct 关键字是从 C 语言中继承过来的


如果使用 class 关键字来定义类,那么定义在第一个访问标号前的任何成员都隐式指定为 private;如果使用 struct 关键字,那么这些成员都是 public。

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

#include <iostream>
#include <string>
using namespace std;

class Student1{
      string name;  //private by default
      int age;      //private by default
public:
       Student1(string s,int i){
            name = s;
            age = i;
       }
       void sayHello(){
            cout << "Hello,my name is " << name << " ,I'm " << age << endl;    
       }
};

struct Student2{
      string name; //all public by default
      int age;
      void sayHello(){
            cout << "Hello,my name is " << name << " ,I'm " << age << endl;    
      }
};

int main()
{   
    Student1 s1("Jack",24);
    //s1.age = 25; ERROR! age is private 
    s1.sayHello();
    
    Student2 s2;
    s2.name = "Tommy";
    s2.age = 35;
    s2.sayHello();
    
    return 0;
}

 

编写自己的头文件

头文件为相关声明提供了一个集中存放的位置,一般包含类的定义、extern 变量的声明和函数的声明。

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

因为头文件包含在多个源文件中,所以不应该含有变量或函数的定义。

对于头文件不应该含有定义这一规则,有三个例外。头文件可以定义类、值在编译时就已知道的 const 对象和 inline 函数。这些实体可在多个源文件中定义,只要每个源文件中的定义是相同的。

一些 const 对象定义在头文件中
因为 const 对象默认为定义它的文件的局部变量,所以把它们的定义放在头文件中是合法的。
当我们在头文件中定义了 const 变量后,每个包含该头文件的源文件都有了自己的 const 变量,其名称和值都一样。

如果 const 变量不是用常量表达式初始化,那么它就不应该在头文件中定义。

预处理器处理程序的源代码,在编译器之前运行。

避免多重包含
使用预处理器定义头文件保护符

预处理器变量 的名字在程序中必须是唯一的。任何与预处理器变量相匹配的名字的使用都关联到该预处理器变量。
为了避免名字冲突,预处理器变量经常用全大写字母表示。

#ifndef STUDENT_H
#define STUDENT_H
class Student{
      string name;  
      int age;      
public:
       Student(string s,int i){
            name = s;
            age = i;
       }
       void sayHello(){
            cout << "Hello,my name is " << name << " ,I'm " << age << endl;    
       }
};
#endif

 

#include <iostream>
#include <string>
using namespace std;
#include "Student.h"
#include "Student2.h"

int main()
{   
    Student s("Jack",35);
    s.sayHello();
    	
    return 0;
}

 不加头文件保护符的话编译出错
 redefinition of `class Student'
 previous definition of `class Student'


补充:
::域操作符,例A::B 意思是取A中定义的B

 

#include <iostream>

namespace Jiangsu{
 char* capital = "Nanjing";
}
int main()
{
 std::cout << Jiangsu::capital << std::endl;
 
 return 0;
}

 

分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics