7.3 Additional Class Features
7.3.1 Class Members Revisited
1.除了可以在类中定义成员以外,还可以自定义某种类型的别名
(1)可以定义在public或者private中
(2)可以用typedef或者using
(3)必须在使用别名前就定义好别名
2.成员函数会自动被设置为inline,我们也可以自己显式设置
3.设置为mutable成员即使在const对象中,也可被更改
7.3.2 Functions That Return *this
1.成员函数返回自身的引用的话,即通过*this,返回的是对象自己本身
2.成员函数也可以被重载且特点差不多
3.const成员函数如果返回自身引用时,必须说明该引用是a reference to const
*可以根据是否为const成员函数进行重载
class Screen{
public:
Screen &display(std::ostream &os){do_display(os);return *this;}
const Screen &display(std::ostream &os) const {do_display(os);return *this;}
private:
void do_display(std::ostream &os) const {os<<contents;}
};
分析:
(1)当no-const函数调用do_display函数时,会将this先转换成a pointer to const,再隐式的传给do_display
(2)const成员函数如果要返回对象本身,返回值类型必须是a reference to const
(3)do_display会隐式的定义为inline,所以既不用重复写代码,还不会浪费花销
7.3.3 Class Types
1.即使两个类定义的所有内容相同,它们仍是不同的类
2.forward declaration:先单独declare某个类而不define它
incomplete type:上面所述的类
限制:只能define pointer或者reference to incomplete type,还有declare(not define) functions that use incomplete type as parameter or return type
即不能实际使用他们
7.3.4 Friendship Revisited
1.在一个类中,不仅可以将外部函数declare为friend,还可以将其他类也declare为friend,这些类中的成员函数可以访问最初这个类中的所有member
2.可以只定义其他类中的某个函数为friend,只要用其他类::函数名就好了
3.就算在类中declare某个外部函数是friend后,也要在类外再次declare这个外部函数,否则不能使用
7.4 Class Scope
1.每个类都有自己的作用域,如果想访问类的成员、函数必须通过member access operator(dot or arrow),如果想访问type member必须用scope operator
2.所以在类外define成员函数时,必须提供类名才行,一当看到类名,define其余部分都在这个类的scope内
void Window_mgr::clear(ScreenIndex i){
Screen &s=screens[i];
s.contents=string(s.height*s.width,' ');
}
分析:
(1)clear需要用scope operator
(2)Window_mgr的成员数据ScreenIndex还有后面的那些并没有需要用scope operator
(3)如果有返回参数也是类中的话,那么就轮到返回类型需要scope operator了,但此时函数名就不用再加scope operator了,当然也是可以加的
7.4.1 name lookup and class scope
1.name lookup:the process of finding which declarations match the use of a name
rule:①在名字出现前的块中寻找声明语句
②如果没有找到则在外层作用域寻找
③如果还没有找到,则程序报错
2.the rule of class definition
rule:①先compile所有declaration
②再compile function body
*member function definitions are processed after the compiler processes all of the declarations in the class
应用和分析看书284页
3.虽然内层作用域可以重新typedef外层作用域名字,但是类中如果成员已经使用了外层作用域某个typedef的type,则不可以重新用这个外层作用域的type的名字
*所以一般类中的typedef要放在最前面,防止与外层作用域的发生冲突
4.如果想要的是外层作用域的名字,可以用显式使用::
vodi Screen::dummy_fcn(pos heigth){
cursor=width*::height; //global one
}
7.5 Constructors Revisited
7.5.1 Constructor Initializer List
1.必须要用initializer list的时候:当成员是const或者是reference或者一个没有default constructor类的对象时
class ConstRef{
public:
ConstRef(int ii);
private:
int i;
const int ci;
int &ri;
}
//error,it is initialized and then assigned,but it can't initialized correctly
ConstRef::ConstRef(int ii){
i=ii;
ci=ii;
ri=i;
}
//correct
ConstRef::ConstRef(int ii)::i(ii),ci(ii),ri(i){}
2.成员初始化的顺序按他们在定义中出现的顺序进行,一般来说不会影响什么,但是如果一个成员的初始化是利用另外一个成员的话,就需要注意
class X{
//i is in front of j
int i;
int j;
public:
//undefined:i is initialized before j
x(int val):j(val),i(j){}
}
3.当给一个构造方法所有参数提供default arguments,相当于提供了一个default constructor
7.5.2 Delegating constructor
1.委托构造函数把自己的职责委托给其他构造函数,先执行受委托的构造函数的初始值列表,再执行它的函数体,最后在执行委托构造函数的的函数体
7.5.3 default constructor
1.当对象被默认初始化或者值初始化时自动执行default constructor
(1)默认初始化:
①define nonstatic variables or arrays at block scope without initializers
②执行合成默认构造函数时,类中有类的类型的成员
③当类的类型的成员没有在Initializer list中显式初始化时
(2)值初始化:
①数组初始化时没有提供所有的元素
②当我们不使用初始值定义一个局部静态变量时
③当我们通过T()的表达式显式地请求值初始化时
7.5.4 类的隐式转换
1.converting constructor:一个参数的构造函数相当于从那个参数类型转换到该类的类型
2.只允许一步的类的类型转换:编译器只会自动地执行一步类型转换
3.如果将构造函数设置为explicit的话,就能抑制类的隐式转换(只能在类中设置为explicit)
4.当我们使用copy form of initialization时,会进行implicit conversion,所以不能用explicit constructor to initialize
5.即使设置为explicit,我们也可以用构造函数进行强制转换
*标准库中参数是const char *的string构造函数不是explicit的,参数是一个容量的vector构造函数是explicit的
7.5.5 Aggregate Classes
1.特点:①all of its data members are public ②not define any constructors ③no in-class initializers ④has no base class or virtual functions
2.作用:可以通过以下方式初始化
struct Data{
int ival;
string s;
}
Data val={0,"Anna"};
//order of argument must appear in declaration order of the data members
7.5.6 Literal Classes
1.literal classes are literal type
7.6 static Class Members
1.the static members of a class exist outside any object
2.access static member:①directly through the scope operator ②use an object to access ③member functions can use static members directly ,without the scope operator
3.static keyword only appear with the declaration inside the class body,but we can define static member function inside or outside of the class body
4.we must define static member data outside the class body,like the member function defined outside the class body with class name::
5.But we can define static const member data inside the class body with in-class initializer.