一、名字空间
C语言中的名字空间的划分:全局、局部、块
C++认为:全局空间用起非常方便,但如果把太多的东西放在全局空间会造成命名冲突,所以C++引用了这样一种机制就是名字空间。
名字空间:把全局的命名空间进一步分割,可以创建出一个个独立的命名空间防止相互之间冲突。
1、定义名字空间:
namespace name
{
变量;
函数;
结构、类;
}
2、名字空间的合并
a、同名的名字空间会自动合并。
b、在同一个名字空间中只标识符必须是唯一的。
3、定义与声明分开
namespace n1
{
//在名字空间中声明函数
void func(void);
}
// 在名字空间外定义函数
void n1::func(void)
{
}
4、如何使用名字空间中的内容
a、域限定符(::),直接使用,名字空间::标识符,这样的好处是绝对不会冲突,但就是麻烦了些。
b、using namespace 名字空间; 功能是把名字空间中的标识符对之后的代码全部公开。
c、using 名字空间::标识符,表示此标识符对后面的代码公开。
5、名字空间的嵌套
名字空间可以嵌套,但使用时要逐层解析。
namespace n1
{
int num = 10;
namespace n2
{
int num = 20;
namespace n3
{
int num = 30;
}
}
}
n1::n2::n3::num == 30;
n1::n2::num == 20;
n1::num = 10;
using namespace n1::n2;
6、全局空间归属为匿名空间
在全局空间定义的标识符都属于这个匿名空间,匿名空间默认开放。
如果函数中有同名的标识符把匿名空间中的屏蔽了,可以使用空的域限定符表示它。
注意:不同命名空间中的同名函数不构成重载,同一作用域下的同名函数叫重载。
二、class
1、C++的class与struct一样,是一种复合数据类型。
2、里面可以有变量用来表达属性,函数用来表示行为。
3、在C++的class与struct,几乎没有任何区别。
4、struct中默认访问属于是public,class中默认的访问属性是private。
5、在C++默认使用class,以示与C语言中的struct进行区分。
三、class的构造函数
1、在创建对象时自动调用的函数,在整个对象的生命周期中一定会被调用一次,且只能被调用一次。
2、在构造函数中负责对成员变量的初始化、分配资源、设置对象的初始状态。
3、构造函数可以有多个版本,这些不同的版本之间会构造重载,创建对象时的方式不同、给的参数不同会调用相应的构造函数,如果调用的构造函数不存在可能会造成编译错误。
// 无参构造
Student stu <=> Student* stup = new Student;
Student stu(参数列表) <=> Student* stup = new Student(参数列表);
4、如果类中没有定义构造函数,编译器会自动生成一个无参构造。
一旦定义了其它版本的构造函数,无参构造就不会再生成了,因此为了防止无参方式创建对象出错,在定构造函数时,至少要实现两个。
5、无参构造未必无参,在C++中函数可以有默认参数,如果有参构造全部设置了默认参数,就会和无参数构造有冲突,它们两个只能有一个存在。
6、所谓的"编译器生成的某某函数"
"编译器生成的某某函数",不是真正意义上的函数,编译作为指令的生成者,只要生成具有某些函数功能的指令即,没有必须生成高级语言的主义上的函数。
7、什么时候调用无参构造
a、Student stu <=> Student* stup = new Student;
b、创建对象数组,每个对象都会调用一次无参构造。
c、如果类A中有成员是类B,当执行守类A的构造函数前会自动调用类B的无参构造。
d、在类A中如何调用类B的有参构造
类A(参数列表):成员类B(参数列表)
{
...
}
8、类型转换构造函数
用一个数据给对象初始化,默认会自动调用构造函数,达到类型转换的效果。
这种方式虽然使用方便,但也会包容一些错误存在,如果想让代码检查更为严格可以使用explicit关键字禁止隐式转换的方式调用构造函数。
9、也可以实现自动类型转换构造函数(默认)。
总结:
- 名字空间:将自己声明的 变量名、函数名、结构名、类名归为一个名字空间,这样便于集中分类管理命名,减少命名冲突。名字空间可以嵌套,同名的名字空间自动合并,并且同一名字空间内标识符是唯一的。 注意:名字空间内可以初始化变量和结构体,但只能函数声明,不能函数定义(名字空间以外才行),使用::域限定符来确定名字空间内标识符的所属关系,其次,通过using namespace 名字空间名 来申请使用该名字空间。
-
namespace n1 { int num = 20; void func(void); } namespace n2 { int num = 100; void func(void); } void n1::func(void) { cout << n2::num << endl; } void n2::func(void) { cout << n1::num << endl; } int main() { n1::func(); n2::func(); }
- 无参数构造函数:1、若未定义类的构造函数,就定义类,那么编译器会给类自动生成构造函数的相关指令。若定义了类的构造函数,编译器就不会自动生成构造函数(相关指令); 2、若需要定义类的具有默认参数的构造函数,一定不能与无参构造函数冲突,若一定会冲突就去掉无参构造函数 ;3、一般会为类定义一个无参函数和一个有参函数。
- 类型转换构造函数:不是很懂,转换类型函数和类型转换构造函数。
练习:
定义一个Date类: year,month,day,在类里提供
1、年月日是否有效,返回bool类型
2、是否是闰年,返回bool类型
3、求nextday() ,返回下一天的日期
4、写一个nextday(int n)表示n表后的日期,注意n可正可负(参考代码https://gitee.com/ZhongShengXueXi/codes/whx5qr4fane8scg3tj91k19)
写一个Timer类(属性定义为私有,方法定义为公开)
有一个属性 usigned int second;//second记录定时器的秒数
有一个属性 Action action;//定时器响应动作
typedef bool (*Action)(void *);
有一个方法setAction(Action a),当调用begin()方法之后,second秒之后自动调用a函数。(参考代码https://gitee.com/ZhongShengXueXi/codes/pg5omuh9wtql1djef8xvy83)