今天学习的还是类这一块。
首先
对于两个类来说,即使他们的成员完全一样,这两个类也是不同的类型。
对于函数来说,有函数声明,其实类也是有类的声明的。
class _Class; // _Class 类的声明
对于类型_Class类来说,在声明后定义前是一个不完全类型,就是说不清楚它包含哪些成员。在实际中,用的很少。
再探友元
之前我学习了非成员函数再类中的友元写法。其实类也可以有类的友元写法。如果一个类指定了友元类,则友元类的成员函数可以访问此类包括非公有成员在内的所有成员。
class People {
friend class Friend;
public:
void display() {
std::cout<<"I'm person"<<std::endl;
}
private:
int m_Age = 0;
};
class Friend {
public:
void update() {
int len = ps.size();
for(int i = 0; i < len; ++i) {
ps[i].m_Age = 0;
}
}
private:
std::vector<People> ps;
};
在这两个类中,Friend类的函数可以修改People类private权限的属性。
同样的,也可以令成员函数作为友元:
class People {
friend void Friend::update();
public:
void display() {
std::cout<<"I'm person"<<std::endl;
}
private:
int m_Age = 0;
};
注意: 要想让某个成员函数作为友元,我们必须按照结构以满足声明和定义的彼此关系。保证要进行友元的类需要的那个类先声明定义和其友元,最后有这个成员函数的定义。
**每个类负责控制自己的友元类或友元函数。**友元关系不存在传递性。就像别人的朋友不一定是你的朋友一样。
重载和友元 与普通重载相同。
友元声明和作用域
**类和非成员函数的声明不是必须在它们的友元声明之前的。**当一个名字第一次出现在一个友元声明中时,我们隐式地假定该名字在当前作用域中是可见地。然而,友元本身不一定真的在当前作用域中。友元声明的作用是影响访问权限,它本身并非普通意义上的声明。
类的作用域
每个类都会有它自己的作用域。在类的外侧,普通数据和函数成员只能由对象、引用或指针使用成员访问运算符来访问。
函数的返回类型通常出现在函数名外面,因此当成员函数定义在类的外部时,返回类型中使用的名字位于类的作用域外面,这时必须要指明它是哪个类的成员。
Person:: pos Person::m_retBirth() {};
名字查找和类的作用域
一般的名字查找:
- 先在所在块中寻找声明语句,只考虑在名字使用之前出现的声明。
- 如果没找到,到外层作用域寻找
- 最终没找到,程序报错
对于定义在类内部的成员函数来说,与上面的有所区别。类的定义分两步:一、首先编译成员的声明;二、直到类全部可见才编译函数体。
编译器处理完类中的全部声明后才开始处理成员函数的定义。
所以,它能使用类中定义的任何名字。
在类中,如果成员使用了外层作用域中的某个名字,而该名字代表一种类型,则类不能在之后重新定义名字。因此,一般类型名的定义通常出现在类开始的地方
class Peron {
public: // 先编译声明 print 和 write
// 所以,print函数里的write也是合法的
// 因为已经处理完全部的声明了,知道write的存在。
void print() {
std::cout<<"1"<<std::endl;
write();
}
void write() {
std::cout<<"dkfjdlkf"<<std::endl;
}
};
成员函数中的普通块作用域的名字查找
- 先在成员函数内查找名字声明。和前面一样,只有在函数使用之前出现的声明才被考虑
- 成员函数内没有找到,则到类内,此时类内所有成员都可以访问。
- 类内没有找到名字声明,就在成员函数定义之前的作用域内找。
一般不建议使用其他成员的名字作为成员的参数。
- 如果成员定义在类的外部时,名字查找不仅要考虑类定义之前的全局作用域中的声明,还要考虑在成员函数定义之前的全局变量中的声明。
声明在定义前面
再探构造函数
就对象的数据成员而言,初始化和赋值也有类似的区别。如果没有再构造函数的初始化列表中显示的初始化成员,则成员将在构造函数体之前执行默认初始化。但是当成员是常量和引用的时候,普通构造函数不能进行初始化。
所有,如果成员是const、引用,或者属于某种未提供默认构造函数的类类型,我们必须通过构造函数初始化列表为这些成员提供初始值。
建议 使用构造函数初始值
成员初始化的顺序
构造函数初始化列表只说明用于初始化的成员的值,而不限定初始化具体的执行顺序。构造函数初始化列表中初始值的前后关系不会影响实际的初始化顺序。
最好零构造函数初始化值得顺序与成员声明一致。尽量避免使用某些成员初始化其他成员。
感觉对名字查找还是不太了解,只知道哥一般的,要多理解理解。