第七章 类
- 定义在类内部的是隐式的inline函数。
- 成员函数通过一个名为this的隐式参数来访问调用它的那个对象。
//names 类名。total 实例名
name total;
total.isTrue();
//等价于
name::isTrue(&toatal);
- const关键字放在成员函数的参数列表之后,代表this是一个指向常量的指针,所指对象不可被更改。
类作用域与成员函数
- 首先编译成员声明,再编译成员函数,因此成员函数可以不用在意类内的成员的声明次序。
- 返回对象的引用。
return *this;
io类不能被拷贝。
构造函数
- 构造函数不能被声明成const,毕竟初始化结束前还要向里面写值。
- 常量对象在其被构造函数初始化完以后才取得常量属性。
- 当类没有声明任何构造函数时,编译器会自动生成默认构造函数;但是如果自己声明了构造函数,默认构造函数就不会自动生成。
- 如果类包含有内置类型或复合类型的成员,则只有当这些成员被初始化以后才适用于合成的默认构造函数。
友元
-
class和struct唯一区别就是默认的访问权限。 -
友元声明只能出现在类的内部,不是类的成员不受其所在区域访问控制级别的约束,只是意思一下这个是我的朋友,可以访问我的私有属性。 -
友元的声明与类本身放在同一个头文件中(类的外部)。 -
类和非成员函数的声明不是必须在他们的友元声明之前,甚至在类的内部定义了函数,也得在类外声明使得该函数可见。
class X{
friend void f(){ /*可以定义在内部*/ };
X(){
f(); //错误,f未在外界声明
}
void g();
void h();
};
void X::g(){ //错误,f未在外界声明
return f();
}
void f(){};
void X::h(){
return f(); //错误,f未在外界声明
}
void f();
void X::h(){
return f(); //正确
}
封装
- 确保用户代码不会无意间破坏封装对象的状态。
- 被封装的类的具体实现可以随时改变,而无需调整用户级别的代码。
可变数据成员
mutable:即使处于const对象之中也可以被改变。
基于const的重载
class Screen{
public:
Screen &display(ofstream& os){
do_display(os);
return *this;
}
const Screen &display(ofstream& os) const{
do_display(os);
return *this;
}
void do_display(ofstream& os) const{
os << contens;
}
}
名字查找与类的作用域
名字查找
- 首先,在名字所在块中查找其声明语句,只考虑在名字使用之前出现的声明。
- 如果没找到,继续查找外层作用域。
- 如果最终没有找到匹配的声明,则程序报错。
类的定义
- 首先,编译成员的声明。
- 直到类全部可见后才编译成员函数体。
默认构造函数
#include<bits/stdc++.h>
using namespace std;
class N{
public:
N(string &){}; //自定义构造函数
//N(){}; //默认构造函数
};
struct A{
//A(){}; //默认构造函数
//N mmem; //有这条语句后不会再生成默认构造函数
};
struct B{
//B(){};
string b = "10"; //初始化b,传入N(string &);
N b;
};
int main(){
A a;
B b;
}
类类型转换
- 编译器只会自动执行一步类型转换。
- explicit抑制类型转换,只对一个实参的构造函数有效。
constexpr构造函数
构造函数不能是const,但字面值常量类的构造函数可以是constexpr函数。
const 和constexpr区别:
-
const 并未区分出编译期常量和运行期常量。 -
constexpr 限定在了编译期常量。 -
constexpr 修饰的函数,返回值不一定是编译期常量。 -
#include<bits/stdc++.h>
using namespace std;
constexpr int f(int i){
return ++i;
}
int i = 5;
int a[f(5)]; //正确,传入的5是常量,编译器可得结果,返回的是constexpr
int b[f(i)]; // 错误,传入的i是变量,需要y计算之后才能知道f的返回值,所以不是constexpr
int main(){
const int m = 0;
int n = 0;
constexpr int i = 10; //正确
constexpr int j = i+1; //正确
constexpr int k = m+1; //正确
constexpr int l = n+1; //错误
return 0;
}
constexpr构造函数用于生成constexpr对象以及constexpr函数的参数或返回类型。
类的静态成员
通常情况下,类的静态成员不应该在类的内部初始化。然而,我们可以为静态成员提供const整数类型的类内初始值,不过要求静态成员必须是字面值常量类型的constexpr 。
#include<bits/stdc++.h>
using namespace std;
class Test{
public:
static int i; //通常类的静态成员不应该在类的内部初始化
void show_k(){
cout << k << ' ';
kkk(k, i); //如果不注释,则必须在类外声明k
}
void kkk(const int &k, int i){ //如果这个函数不注释,则必须在类外声明k
cout << k << ' ';
}
private:
static constexpr int k = 10; //可以为静态成员提供const整数类型的类内初始值,要求静
//态成员必须是字面值常量类型的constexpr
static int init_k(){
return 1;
};
};
constexpr int Test::k; //类外声明静态成员k,必须声明。
int Test::i = 0; //类外定义静态成员
int main(){
Test a;
a.show_k(); //正确,调用公有成员访问私有成员
//cout << a.k; //错误, 类实例对象不可直接访问私有成员
//cout << Test::k; //错误,不可访问类Test私有成员
cout << Test::i;
return 0;
}
|