C++知识小记

基础思想上

面向对象特征,有说三大的yb

输入输出:

iostream库
标准库定义了 4 个标准 IO 对象。
cin、cout、cerr、clog
默认的,它们将内容输入或输出到当前程序执行的窗口。
可以通过重定向将它们与其它文件等联系起来,然后输入或输出到哪里。
std::cout << xxx
这个表达式返回值是std::cout,所以后面可以直接上<<,变成
std::cout << A<<B

endl 是一个特殊值,称为 操纵符,将它写入输出流时,具有输出换行的效果,并刷新与设备相关联的 缓冲区。

程序员经常在调试过程中插入输出语句,这些语句都应该刷新输出流。忘记刷新输出流可能会造成输出停留在缓冲区中,如果程序崩溃,将会导致程序错误推断崩溃位置。

通常,#include 指示应出现在任何函数的外部。而且习惯上,程序的所有 #include 指示都在文件开头部分出现。

:: 作用域操作符

代码改变时,注释应与代码保持一致。程序员即使知道系统其他形式的文档已经过期,还是会信任注释,认为它会是正确的。错误的注释比没有注释更糟,因为它会误导后来者。

注意注释号包括/* *///引号 " 的优先级一样高,编译器先读到谁就以谁为准,如
/*"*/"abc" 相当于第一个引号被注掉,而
"/*"*/ 语法错误,相当于第一个注释被引起来了

小点:退出 for 循环后,变量 val 不再可访问,循环终止后使用 val是不可能的。然而,不是所有的编译器都有这一要求。

判断输入结束可以这样写:
while (std::cin >> value)
使用 istream 对象作为条件,结果是测试流的状态。遇到文件结束符或遇到无效输入时,如读取了一个不是整数的值,则 istream 对象是无效的,好像是null?)。处于无效状态的 istream 对象将导致条件失败。

C++标准规定了每个算术类型的最小存储空间,但它并不阻止编译器使用更大的存储空间。事实上,对于 int 类型,几乎所有的编译器使用的存储空间都比所要求的大。

long double 类型用三个或四个字(96 或 128 位)来表示。
char 类型是整型。

使用 double 类型基本上不会有错。在 float 类型中隐式的精度损失是不能忽视的,而 double 类型精度代价相对于 float 类型精度代价可以忽略。事实上,有些机器上,double类型比 float 类型的计算要快得多。

以 0(零)开头的字面值整数常量表示八进制,以 0x 或 0X 开头的表示十
六进制。注意这个0开头,反数学反常识的,不注意你肯定觉得int x = 09;这句话是对的,错了,八进制不能超过9,这是见后面的一道错题

注意,C++里面各种基本类型的长度并不是一定的,即int不一定是32位,
① C/C++规定int字长和机器字长相同;
② 操作系统字长和机器字长未必一致;
③ 编译器根据操作系统字长来定义int字长;
用的时候要注意取值范围不够,溢出的可能。如16为的话,超过32767就不行了

注意,反人类的C++ 不能在整数字面量后面加一个f将它转换成浮点数

使用科学计数法时,指数用 E 或者 e 表示。2e8f=2*10^8。这里加f是因为当成小数了。

C++不同类型赋值特点:

1、将超出其取值范围的数赋值给unsigned时,取余,将超出取值范围的数赋值给signed时,标准没有规定,取决于编译器,通常也是取余

C++ 被设计成允许程序在必要时直接处理硬件

不要依赖未定义行为

使用了未定义行为的程序都是错误的,即使程序能够运行,也只是巧合。未定义行为源于编译器不能检测到的程序错误或太麻烦以至无法检测的错误。不幸的是,含有未定义行为的程序在有些环境或编译器中可以正确执行,但并不能保证同一程序在不同编译器中甚至在当前编译器的后继版本中会继续正确运行,也不能保证程序在一组输入上可以正确运行且在另一组输入上也能够正确运行。

程序不应该依赖未定义行为。 同样地,通常程序不应该依赖机器相关的行为,比如假定 int 的位数是个固定且已知的值。我们称这样的程序是不可移植的。当程序移植到另一台机器上时,要寻找并更改任何依赖机器相关操作的代码。在本来可以运行的程序中寻找这类问题是一项非常不愉快的任务。

标识符

当一个定义中定义了两个以上变量的时候,每个变量都可能有自己的初始化式。 对象的名字立即变成可见,所以可以用同一个定义中前面已定义变量的值初始化后面的变量。
C++里面变量名、函数名、类名不能相同,这和Java不一样,因为函数指针会和变量名冲突等原因。

C++ 标准还保留了一组标识符用于标准库。为了不引起冲突,建议最好标识符不能包含两个连续的下划线,也不能以下划线开头后面紧跟一个大写字母。有些标识符(在函数外定义的标识符)不能以下划线开头。

错题:
1、int month =09, day = 07;
如果上述定义有错的话,那么应该怎样改正呢?
而 month 的初始化有错:试图将 month
初始化为八进制值 09,但八进制数字范围为 0~7,所以出
错。可将第二个定义改为:int month =011, day = 07;

2、下面哪些是非法定义?改正所有的非法定义。
(a) int car = 1024, auto = 2048;
(b) int ival = ival;
© std::cin >> int input_value;
(d) double salary = wage = 9999.99;
(e) double calc = calc();

(a) 非法:auto 是关键字,不能用作变量名。使用另一变量
名,如 aut 即可更正。
© 非法:>>运算符后面不能进行变量定义。改为:int
input_value;std::cin >> input_value;
(d) 非法:同一定义语句中不同变量的初始化应分别进行。
改为:double salary = 9999.99, wage = 9999.99;
注意,(b)虽然语法上没有错误,但这个初始化没有实际意义,
ival 仍是未初始化的。

默认构造函数相关,和Java类似:
有些类类型没有默认构造函数。对于这些类型来说,每个定义都必须提供显式的初始化式。

作用域

由大到小
全局——名字定义在任何其他作用域外。
命名空间——名字在命名空间中定义,除匿名外,它可以在文件外访问,所以比文件作用域大的。
文件作用域——cpp文件下直接定义且使用static修饰的,在文件范围内有效。
类——名字由类定义。
局部或块——函数内定义或者名字定义在语句块中,也就是说,定义在一对花括号里,外面不能用,Java里面一样,自己竟然不知道。
函数原型作用域——函数声明语句里面,函数参数括号内的参数变量,作用域=那对括号

生存周期和存储类型

实际上生存周期是作用域对等的变量的另一大特性,作用域表明变量的空间特性,生存周期表明时间特性。
C++中变量的生存周期和存储位置紧密相关,C++程序的存储区域可分为代码区和静态数据区,堆区,栈区。根据下面的,放在静态区的生命周期就和程序一样。

C++语法有规定,声明变量时,除了声明数据类型外还应该声明存储类型。
存储类型有
auto: C语言规定, 函数内凡未加存储类型说明的变量均视为自动变量, 也就是说自动变量可省去说明符auto。
extern:详见下面
static:静态变量static
register:寄存器变量。顾名思义,但是现在都是编译器优化了,不用写了,写了也不一定有用。

和Java代码文件有区分的一点是:
Java代码文件只允许文件下面出现类层级的结构,即类,接口,枚举这些,但C/C++等则没有限定,任何结构都允许出现。貌似很多语言偏向于C这个风格。

小点
if (int x = 1) {

}
这也是可以的,x作用域在if后面的括号完为止,应该是和for一样的语法。

extern 关键字声明变量

1、在一个文件的的最外面定义的,即不在函数,类,命名空间等等里面的,就叫外部变量。在其它文件中不用包含头文件,直接用extern 关键字声明外部变量,就可以使用了。这种情况下,比#inlude<头文件> 的方式包含的东西更少。外部函数类似。即当一个源程序由若干个源文件组成时, 在一个源文件中定义的外部变量在其它的源文件中也有效。
不过通常的使用方式是在头文件中使用extern
extern int i; // declares but does not define i
int i; // declares and defines i
2、extern 声明不是定义,也不分配存储空间。事实上,它只是说明变量定义在程序的其他地方。程序中变量可以声明多次,但只能定义一次。
任何在多个文件中使用的变量都需要有与定义分离的声明。在这种情况下,一个文件含有变量的定义,使用该变量的其他文件则包含该变量的声明(而不是定义)。

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

如果一个文件中定义的外部变量或者方法不想被其它文件访问,则可以使用匿名的命名空间或者static,这样其它文件就访问不到了。

extern也相当于把一个变量变成全局的变量了,有时候不好用,通常的做法是提供方在自己的xxx_pub.h中提供对外部接口的声明,然后调用方include该头文件,从而省去extern这一步。

从另外的角度上说,用extern会增加耦合性,而且难以捕捉在哪儿进行了修改。

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

static关键字

static修饰局部变量,改生存周期变成和程序的一样,如用在类里面,就是类变量,相当于Java类里面的静态变量。用到函数里面,函数执行完,它不回收,值一直保存着。
static修饰全局变量和方法,用于限制作用域,控制访问,反常语法… 加上static之后,不能被其它文件用extern引用,注意#include包含之后还是可以用的,只能作用在本文件,生存周期没变。然后能避免名字冲突。

引用

不能定义引用类型的引用,但可以定义任何其他类型的引用。
当引用初始化后,只要该引用存在,它就保持绑定到初始化时指向的对象。不可能将引用绑定到另一个对象。定义引用时没有初始化是错误的
注意这个机制,第一次用等号对引用赋值,&r=a,是让它指向a,后面再用等号赋值,那是改变a的值,也就是第一次对引用赋值和后面对引用赋值意义不一样。

函数返回类型后面加个&符号,表示返回引用,这和直接返回值不一样。

常引用

常引用可以指向常对象和非常对象。**而非常引用只能指向非常对象,不能指向常对象。**常引用指向非常对象是,方法规则和常对象访问规则一样了。

const int ival = 1024;
const int &refVal = ival; // ok: both reference and object areconst
int &ref2 = ival; // error: non const reference to a const object

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

常对象

常对象,常对象的成员对象都看作常量,不管有没有声明为常量。
小点,有一种特殊情况,某些情况下即希望声明对象为常对象,又希望通过常对象改变某个变量,此时就得在改变量前面加上mutable修饰,这样就能在常对象或者常函数里面修改它了,不过这个关键字要慎用才行
常对象不能访问一般方法,只有加了const声明的方法可以访问,如int abs(xxx) const {} 叫做常函数。
constu虽然很多时候推荐使用,但是在不确定的时候不要乱用,很多时候这个东西导致各种非常量不能访问,声明与定义不一致,反倒麻烦。

常数据成员

常数据成员只能在构造函数的初始化列表中初始化。

常函数

常函数规则:1、声明和定义的地方都要带const 2、不能修改成员对象 3、不能调用非常成员函数 4、可以用作函数重载的区分 调用时非常对象调用同名的非常方法,常对象调用同名的常方法。
一般来说,对于不会改变对象成员的方法,加上一个const,是一个好习惯。

注意,C中浮点数可以直接赋值给整数。等。如:
int ival = 1.01;是对的,Java中不对

typedef 可以用来定义类型的同义词:
typedef double wages; // wages is a synonym for double
typedef int exam_score; // exam_score is a synonym for int
typedef wages salary; // indirect synonym for double

枚举的定义包括关键字 enum,其后是一个可选的枚举类型名,和一个用花
括号括起来、用逗号分开的 枚举成员列表。
// input is 0, output is 1, and append is 2
enum open_modes {input, output, append};

枚举成员是常量 用来初始化枚举成员的值必须是一个 常量表达式。
enum Points { point2d = 2, point2w,point3d = 3, point3w };
本例中,枚举成员 point2d 显式初始化为 2。下一个枚举成员 point2w 默
认初始化,即它的值比前一枚举成员的值大 1。因此 point2w 初始化为 3。枚
举成员 point3d 显式初始化为 3。一样,point3w 默认初始化,结果为 4。

数据则称为 数据成员。
类也可以包含 0 个到多个 private 或 public 访问标号。访问标号控制类的成员在类外部是否可访问。使用该类的代码可能只能访问 public 成员。

C++ 支持另一个关键字 struct,它也可以定义类类型。struct 关键字是从C 语言中继承过来的。

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

string类

string s4(n, ‘c’); 将 s4 初始化为字符 ‘c’ 的 n 个副本
字符串字面值与标准库 string 类型不是同一种类型。
cin >> s; // read whitespace-separated string into s
从标准输入读取 string 并将读入的串存储在 s 中。string 类型的输入操
作符:
读取并忽略开头所有的空白字符(如空格,换行符,制表符)。
• 读取字符直至再次遇到空白字符,读取终止。

getline 函数将 istream 参数作为返回值,和输入操作符一样也把它用作
判断条件。
while (getline(cin, line))
cout << line << endl;

从逻辑上来讲,size() 成员函数似乎应该返回整形数值,或如 2.2 节“建议”中所述的无符号整数。但事实上,size 操作返回的是 string::size_type 类型的值。因为有些情况下int不够大。

string st1, st2 = “The expense of spirit”;
st1 = st2; // replace st1 by a copy of st2
赋值操作后,st1 就包含了 st2 串所有字符的一个副本。
大多数 string 库类型的赋值等操作的实现都会遇到一些效率上的问题,但值得注意的,从概念上讲,赋值操作确实需要做一些工作。它必须先把 st1 占用的相关内存释放掉,然后再分配给 st2 足够存放 st2 副本的内存空间,最后把 st2 中的所有字符复制到新分配的内存空间。和Java不同,得赋值整个空间。string里面用指针保存实际的字符数组,复制的时候采用深拷贝。

C++里面不能单独把多个字符串字面量相加,但是如果其中有一个或多个变量就行。比如s=“a”+“b”; 不行 s1=s + “a” + “b” 是可以的。

各种字符操作函数,适用于 string 对象的字符(或其他任何 char 值)。这些函数都在cctype 头文件中定义。如
isalnum© 如果 c 是字母或数字,则为 True。
isalpha© 如果 c 是字母,则为 true。
等等

vector

因为 vector 增长的效率高,在元素值已知的情况下,最好是动态地添加元素。和Java的ArrayList不同
v.push_back(t) 在 v 的末尾增加一个值为 t 的元素。
v1 == v2 如果 v1 与 v2 相等,则返回 true。
!=, <, <=, >, and >=
保持这些操作符惯有的含义。

for (vector::size_type ix = 0; ix != ivec.size(); ++ix)
ivec[ix] = 0;
在 C++ 中,有些数据结构(如vector)可以动态增长。上例中循环仅需要读取元素,而不需要增加新的元素。但是,循环可以容易地增加新元素,如果确实增加了新元素的
话,那么测试已保存的 size 值作为循环的结束条件就会有问题。所以我们倾向于在每次循环中测试 size的当前值,而不是在进入循环前,存储 size 值的副本。

若一种类型支持一组确定的操作(这些操作可用来遍历容器内的元素,并访问这些元素的值),我们就称这种类型为迭代器。

vector 迭代器的自增和解引用运算

迭代器类型可使用解引用操作符(dereference operator)(*)来访问迭
代器所指向的元素:
*iter = 0;
解引用操作符返回迭代器当前所指向的元素。假设 iter 指向 vector 对象 ivec 的第一元素,那么 *iter 和 ivec[0] 就是指向同一个元素。
++iter效果就是 “向前移动一个位置”

由于 end 操作返回的迭代器不指向任何元素,因此不能对它进行解引用或自增操作。

bitset

而与 vector 不一样的是 bitset 类型对象的区别仅在其长度而不在其类型。在定义 bitset 时,要明确 bitset 含有多少位,须在尖括号内给出它的长度值。尖括号里面给出的不是类型而是长度。如 bitset b; b 有 n 位,每位都 0
1、用 unsigned long 值作为 bitset 对象的初始值。bitset b(u); bitset<16> bitvec1(0xffff);
如果 bitset 类型长度大于 unsigned long 值的二进制位数,则其余的高阶位将置为 0;如果 bitset 类型长度小于 unsigned long 值的二进制位数,则只使用 unsigned 值中的低阶位,超过 bistset 类型长度的高阶位将被丢弃。
2、当用 string 对象初始化 bitset 对象时,string 对象直接表示为位模式。
**从 string 对象读入位集的顺序是从右向左(from right to left):**注意是反向的。
可以只用某个子串作为初始值: bitvec5(str, 5, 4);

3、多种 bitset 操作(表 3.7)用来测试或设置 bitset 对象中的单个或多个
二进制位。
b.any() b 中是否存在置为 1 的二进制位?
b.none() b 中不存在置为 1 的二进制位吗?
b.set(pos) 把 b 中在 pos 处的二进制位置为 1
b.flip(pos) 把 b 中在 pos 处的二进制位取反
unsigned long ulong = bitvec3.to_ulong();

数组:

现代 C++ 程序应尽量使用 vector 和迭代器类型,而避免使用低级的数组和指针。设计良好的程序只有在强调速度时才在类实现的内部使用数组和指针。
数组的长度是固定的,而且程序员无法知道一个给定数组的长度。数组没有获取其容量大小的 size 操作。

1、数组的维数(长度)必须用值大于等于 1 的常量表达式定义。
2、可为其元素提供一组用逗号分隔的初值,这些初值用花括号{}括起来,称为初始化列表。
3、如果没有显式提供元素初值,则数组元素会像普通变量一样初始化。
4、显式初始化的数组不需要指定数组的维数值,编译器会根据列出的元素个数来确定数组的长度:
int ia[] = {0, 1, 2}; // an array of dimension 3
5、如果维数大于列出的元素初值个数,则只初始化前面的数组元素;剩下的其他元素,若是内置类型则初始化为 0,若是类类型则调用该类的默认构造函数进行初始化
6、不管数组在哪里定义,如果其元素为类类型,则自动调用该类的默认构造函数进行初始化;如果该类没有默认构造函数,则必须为该数组的元素提供显式初始化。
7、字符数组既可以用一组由花括号括起来、逗号隔开的字符字面值进行初始化,也可以用一个字符串字面值进行初始化。然而,要注意这两种初始化形式并不完全相同,字符串字面值(第 2.2 节)包含一个额外的空字符(null)用于结束字符串。
8、与 vector 不同,一个数组不能用另外一个数组初始化,也不能将一个数组赋值给另一个数组,这些操作都是非法的。一些编译器允许将数组赋值作为 编译器扩展。但是如果希望编写的程序能在不同的编译器上运行,则应该避免使用像数
组赋值这类依赖于编译器的非标准功能。

高维指针与高维数组

高维数组在内存上是连续分配的,别以为是分配的矩阵样子的二维内存空间。计算机内存空间是一维的,分配个二维的矩阵空间出来,很麻烦的。然后计算的时候,编译器进行了下标的转化而已。
基于上面,高维数组可以相当于指向低维数组的指针,+1,移动低一维数组的长度,移动n个字长。
高维指针指向的是低一维的指针,仍然是指向指针的指针,+1移动字长。
高维数组和高维指针是不一样的,一维的情形比较特殊,数组可以赋值。但是高维的就不行了。
以二维为例,二维指针的第一维存放的是指针,而二维数组没有第一维,因此二维数组名不能赋值给二维指针。就算假如赋值了,a[m][n], **p = a; 相当于p指向a[0][0]的位置,然后对于*p是取p所指向的地址后面32位(假设32位)形成的值,应当是一个指针。然而a[0][0]后面32位是一个数。
赋值的时候,高维指针可以用低一维指针的数组赋值,高维数组可以用低一维数组的指针赋值,但是换过来不行的。

高维数组传参

高维数组传参,第一维可以不写长度,后面的必须写,根据前面的数组原理,如二维数组,那样编译器才能知道行的长度,才能计算元素位置。而对于列,不用限制,编译器人可以计算。
高维数组可以传递给低一维数组的指针变量。如int a[10][10]传递给int (*p)[10]

函数指针数组
void (Widget::*pa[4])(); //定义了一个函数指针指针数组

小点:sizeof(高维数组)=数组总大小
sizeof(高维指针)=指针本身的大小

int ia2[](ia); // error:
ia3 = ia; // error:
10、vector 使用 vector::size_type 作为下标的类型,而数组下标的正确类型则是 size_t(第 3.5.2 节)。
for (size_t ix = 0; ix != array_size; ++ix)
ia[ix] = ix;

指针

1、指针对于数组,相当于迭代器对于vector等容器:
在指向数组元素的指针上使用解引用操作符 *(dereferenceoperator)和自增操作符 ++(increment operator),与在迭代器上的用法类似。
数组名和指针两者的区别还很大,不能看成一样的。

建议:尽量避免使用指针和数组 建议:尽量避免使用指针和数组

指针和数组容易产生不可预料的错误。其中一部分是概念上的问题:指针用于低级操作,容易产生与繁琐细节相关的(bookkeeping)错误。其他错误则源于使用指针的语法规则,特别是声明指针的语法。许多有用的程序都可不使用数组或指针实现,现代 C++程序采用 vector类型和迭代器取代一般的数组、采用 string 类型取代 C 风格字符串。

2、string* ps1, ps2; // ps1 is a pointer to string, ps2 is a string
实际上只把 ps1 定义为指针,而 ps2 并非指针,只是一个普通的 string对象而已。如果需要在一个声明语句中定义两个指针,必须在每个变量标识符前再加符号 * 声明

3、一个有效的指针必然是以下三种状态之一:保存一个特定对象的地址;指向某个对象后面的另一对象;或者是 0 值。若指针保存 0 值,表明它不指向任何对象。未初始化的指针是无效的,直到给该指针赋值后,才可使用它
4、避免使用未初始化的指针,它几乎总会导致运行时崩溃。在对未初始化的指针进行解引用时,通常会导致程序崩溃。C++ 语言无法检测指针是否未被初始化,也无法区分有效地址和由指针分配到的存储空间中存放的二进制位形成的地址。建议程序员在使用之前初始化所有的变量,尤其是指针。
如果可能的话,除非所指向的对象已经存在,否则不要先定义指针,这样可避免定义一个未初始化的指针。
5、C 语言中继承下来的预处理器变量 NULL(第 2.9.2 节),该变量在 cstdlib头文件中定义,其值为 0。
6、C++ 提供了一种特殊的指针类型 void*,它可以保存任何类型对象的地址。与另一个指针进行比较;向函数传递 void 指针或从函数返回 void 指针;给另一个 void 指针赋值。不允许使用void 指针操纵它所指向的对象。void指针也用起来也很危险,一般避免使用。
7、常指针、指向常量的指针、指向常量的常指针

常指针:int *const p,或者称为p常指针,地址(p)不能变 ,内容(*p)可以变
与任何 const 量一样,const 指针也必须在定义时初始化。指针本身的值不能修改,但它所指向的对象的值是否能修改,取决于对象的情况,是否为常量等

指向常量的指针:const int *p = 4;或者称为*p常指针,他只是要求了*p是常量,内容(*p)可以变,地址(p)可以变。注意指向的变量并不要求是常量
常量只能赋给指向常量的指针,但指向常量的指针既能用常量赋值,又能用非常量赋值,指向常量的指针不会改变这个非常量,自然是允许的

指向常量的常指针,自然地,二者结合,都不能变

C++的类型转换函数

static_cast 比较安全的转换,一般是内容上的转换。
const_cast 将常量转化成非常量,危险操作,特殊情况下使用。
reinterpret_cast 转换指针,很不安全,特殊情况下使用。

C中结构体定义的方式

一、最基本的
struct A{
}
struct A a;
由于要加上一个struct比较麻烦。貌似现在的编译器能够不谢struct了
二、定义的同时定义变量
struct A{
} a;
三、匿名的结构体
struct {
}a;
只能定义结构体的同时定义变量;
四、使用typedef 简化
typedef struct A{
} NA;
NA a;

一些细节:
scanf里面函数非控制、非格式字符,输入的时候也需要输入相应的字符,如scanf(“a=%d”, a);输入的时候也需要先输入a=;
数组名做实参实际上传递了一个指针进去,在函数里面用sizeof得不到数组大小,结果是指针大小,如=4等。

其它:
C++的函数覆盖要求子类的返回值类型必须和父类的一样,和Java不同。貌似C++没有类似Java的泛型限定那种功能。

一些题目:
定义常量,使用const而不使用#define的原因是什么?
const具有类型,可以进行类型检测,并且能在编译时可见,而#define不行

3-5 函数原型中的参数名与函数定义中的参数名以及函数调用中的参数名必须一致吗?
 解:   不必一致,所有的参数是根据位置和类型而不是名字来区分的。

5-2 什么叫做可见性?可见性的一般规则是什么?
解:
可见性是标识符是否可以引用的问题;
可见性的一般规则是:标识符要声明在前,引用在后,在同一作用域中,不能声明同名的标
识符。对于在不同的作用域声明的标识符,遵循的原则是:若有两个或多个具有包含关系的
作用域,外层声明的标识符如果在内层没有声明同名标识符时仍可见,如果内层声明了同名
标识符则外层标识符不可见。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值