函数原型作用域是c++程序中最小的作用域。函数原型声明时形式参数的作用范围就是函数原型的作用域
double area(double radius)
radius的作用域就在函数area形参列表的左右括号之间。(以我目前看来,没发现有什么作用)
类X的成员m具有类作用域,对m的访问方式有如下3种:
1.如果在X的成员函数中没有声明同名的局部作用域标识符,那么在该函数内可以直接访问成员m
2.通过表达式x.m或者X::m,这正是程序中访问对象成员的最基本方法
3.通过ptr->m这样的表达式,其中ptr为指向X类中的一个对象的指针
命名空间名::标识符名
namespace someNS{
class SomeClass{……};
}
someNS::SomeClass obj1;
using 命名空间名::标识符名;(将指定标识符暴露在当前作用域内,当前作用域可以直接引用)
using namespace 命名空间名;
namespace outerNS{
namespace InnerNS{
class SomeClass{……};
}
}
outerNS::InnerNS::SomeClass(如需引用的格式)
namespace{
各类声明
}
匿名命名空间常常被用来屏蔽不希望暴露给其他源文件的标识符,这是因为每个源文件的匿名命名空间是彼此不同的,在一个源文件中没有办法访问其他源文件的匿名命名空间。
具有命名空间作用域的变量也称为全局变量
main函数内定义的变量是局部变量,只不过生存期同全局变量
全局变量一定是定义在函数外的
程序运行到某一点,能够引用到的标识符,就是该处可见的标识符
如果对象的生存期与程序的运行期相同,则称它具有静态生存期(全局变量)
在命名空间作用域中声明的对象都是具有静态生存期
如果要在函数内部的局部作用域中,声明具有静态生存期的对象,则要用关键字static
细节:定义时未指定初值的基本类型静态生存期变量,会被赋予0值初始化,而对于动态生存期变量,不指定初值意味着初值不确定
除了上述两种情况,其余的对象都具有动态生存期
诞生于声明点,结束于声明所在的块执行完毕
类属性是描述类的所有对象共同特征的一个数据祥,对于任何对象实例,它的属性值是相同的
在类的定义中仅仅对静态数据成员进行引用性声明,必须在命名空间作用域的某个地方使用类名限定定义性声明,这时也可以进行初识化(类的静态成员变量在使用前必须进行初始化)
静态成员函数可以通过类名(推荐)或对象名(不推荐)来调用,而非静态成员函数只能通过对象名来调用
静态成员函数可以直接访问该类的静态数据和函数成员,而访问非静态成员,必须通过对象名(其实这里的意思并不是跟后面的矛盾了,as you know, 类的静态成员函数调用非静态成员是不被允许的,但是这里的访问非静态成员的意思是指像任何一个普通的函数一样,使用对象名来调用)
1.类的非静态成员函数使用类的静态成员 ✔
2.类的静态成员函数使用类的非静态成员 ×(因为静态成员函数属于整个类,在类实例化对象之前就已经分配空间了,而类的非静态成员必须在类实例化对象后才有内存空间,所以这个调用就出错了,就好比没有声明一个变量却提前使用它一样)
友元关系提供了不同类或对象的成员函数之间、类的成员函数与一般函数之间进行数据共享的机制
友元函数是在类中用关键字friend修饰的非成员函数(即使它不是本类的成员函数,但是在它的函数体中可以通过对象名访问类的私有和保护成员)
上面例子中,在Point类中只声明了友元函数的原型(dist不是Point类的成员函数),友元函数dist的定义在类外
若A类为B类的友元类,则A类的所有成员函数都是B类的友元函数,都可以访问B类的私有和保护成员
class B{
friend class A;
}
注:
1.友元关系是不能传递的(B类是A类的友元,C类是B类的友元,C类和A类之间,如果没有声明,就没有任何友元关系)
2.友元关系是单向的
3.友元关系是不被继承的
常对象的数据成员值在对象的整个生存期间内不能被改变,常对象必须进行初始化,而且不能被更新
const A a(3,4);
常对象只能调用它的常成员函数,而不能调用其他成员函数
常成员函数不能更新目的对象的数据成员,也不能针对目的对象调用没有用const修饰的成员函数
函数类型说明符 函数名(参数表) const
例子中定义了一个const R b(20,52),所以b的print可以调用数据成员(数据成员也是const)
其中,a也可以调用常成员函数——非 常对象可以调用常成员函数
构造函数对该数据成员进行初始化,就只能通过初始化列表,不能自己直接给常成员变量赋值
常引用所引用的对象不能被更新
如果常引用作形参,便不会意外地发生对实参的更改
const 类型说明符 &引用名
1.非const的引用只能绑定到普通的对象,而不能绑定到常对象,但常引用可以绑定到常对象
2.一个常引用,无论绑定到一个普通对象,还是常对象,通过该引用访问该对象是,都只能把该对象当作常对象(也就是不能调用它的非const的成员函数)
习惯:
对于在函数中无需改变其值的参数,不宜使用普通引用方式传递,因为那会使得常对象无法被传入,采用传值方式或传递常引用的方式可避免这一问题
对于大对象来说,传值耗时较多,因此传递常引用为宜
复制构造函数的参数一般也宜采用常引用传递
通常一个项目至少划分为3个文件:
1.类定义文件(…… .h)
2.类实现文件(…… .cpp)
3.类的使用文件(…… .cpp,主函数文件)
#include<文件名>按照标准方式搜索要嵌入的文件(一般要嵌入系统通过的标准文件时采用这样的方式)
#include"文件名"首先在当前目录下搜索要嵌入的文件,如果没有,在按照标准方式搜索(对用户自己编写的文件一般采用这种方式)
将需要分配空间的定义放在源文件中(函数的定义(需要为函数代码分配空间)、命名空间作用域中变量的定义(需要为变量分配空间))等;而将不需要分配空间的声明放在头文件中,例如类声明,外部函数的原型声明、外部变量的声明、基本数据类型常量的声明等
在其他文件中如果需要使用这个变量,需要在其他文件中用extern关键字声明
对外部变量的声明可以是定义性声明,即在声明的同时定义(分配内存,初始化),也可以是引用性声明(引用在别处定义的变量)
外部变量可以有多处声明,但是对变量的定义性声明只能是唯一的
如果没有特殊说明,所有类之外声明的函数都可以在不同的编译单元中被调用(所以,就是不加extern,也能在别的文件中使用)
不希望一个源文件中定义的命名空间作用域的变量和函数被其他源文件引用
static修饰(曾经,但现在不推荐)
使用匿名空间:
namespace{
int n;
void f(){
n++;
}
}
在编译器对源程序进行编译之前,首先要由预处理器对程序文本进行预处理
所有的预处理指令在程序中都是以“#”来引导
#define在c++可以被替代(const和内联函数)
#define "MYHEAD_H"仅仅表示“MYHEAD_H”定义过
#undef的作用是删除由#define定义的宏,使之不再起作用
1.
#if 常量表达式
程序段
#endif
2.
#if 常量表达式
程序段1
#else
程序段2
#endif
3.
#if 常量表达式1
程序段1
#elif
程序段2
#elif
程序段3
#else
程序段4
#endif
4.
#ifdef 标识符 \\表示如果定义了……,则执行程序段1
程序段1
#else
程序段2
#endif
5.
#ifndef 标识符 \\表示如果没定义过,则执行程序段1
程序段1
#else
程序段2
#endif
defined是一个预处理操作符,而不是指令,因此不要以#开头
#ifndef MYHEAD_H
等值于
#if!defined(MYHEAD_H)