class Screen
{
public:
typedef std::string::size_type pos;
//using pos = std::string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c):height(ht), width(ws),
contents(ht * wd,c){}
//Fills the string with ht * w consecutive copies of character c.
char get() const //读取光标处的字符
{ return contents[cursor]; } //隐式内联
inline char get(pos ht, pos wd) const; //显示内联
Screen &move(pos r, pos c); //定义时设置为内联
private:
pos cursor = 0;
pos height = 0;
pos width = 0;
std::string contents;
};
inline
Screen &Screen::move(pos r, pos c) const
{
pos row = r * width;
cursor = row + c;
return *this;
}
char Screen::get(pos r, pos c) const
{
pos row = r * width;
return contents[row + c];
}
定义在类内部的函数自动inline,可以在类内部把inline作为声明的一部分显示声明成员函数,也可以在类的外部用inline关键字修饰函数的定义。
class Window_mgr
{
private:
std::vector<Screen> screens{Screen(24, 80, ' ')};
}
需要默认初始值的时候最好把这个默认值声明成一个类内初始值。
可变数据成员
可以通过在变量的声明中加入mutable关键字使可以在一个const成员函数中修改类的某个数据成员。mutable data member永远不会是const,即使它是const对象的成员。
class Screen
{
public:
void some_member() const;
private:
mutable size_t access_ctr;
};
void Screen::some_member() const
{
++access_ctr;
}
基于const的重载
一个const成员函数如果以引用的形式返回*this,那么返回的类型会是常量引用。如下所示:
Class_Name &function(...) const;
通过区分成员函数是否是const的,可以对其进行重载,原因和根据参数指针是否指向const而重载函数的原因差不多。(1.常量对象只能调用const成员函数,调用不了非const成员函数2.非常量对象调用非常量版本函数更匹配)
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;}
//其他成员函数与之前版本一致
};
当非常量display函数调用do_display时,this指针隐式的从指向非常量的指针转换成指向常量的指针。
Screen myScreen(5, 3);
const Screen blank(5, 3);
myScreen.set('#').display(cout); //调用非常量版本
blank.display(cout); //调用常量版本
建议:对于公共代码使用私有功能函数(为什么调用do_display)。
原因:
- 避免在多处使用同样的代码。
- 类的规模发展可能是display函数变得更加复杂。此时,把相应操作写在溢出而非两处的作用更明显
- 已添加或删除一些调试信息
- do_display是隐式内联函数,额外的函数调用不会增加任何开销
友元
友元类
成员函数作友元
程序代码
必须仔细组织程序的机构以满足声明和定义的彼此依赖关系。在示例中,按照如下方式设计:
- 首先定义Window_mgr类,其中声明clear函数,但不能定义它。在clear使用Screen的成员之前必须声明Screen
- 接下来定义Screen,包括对于clear的友元声明
- 最后定义clear,此时它才可以使用Screen的成员
函数重载和友元
如果一个类想把一组重载函数声明成它的友元,需要对这组函数的每一个分别声明。
友元声明和作用域
类和非成员函数的声明不是必须在它们的友元声明之前。就算在类的内部定义友元函数,也必须在类的外部提供相应声明从而使函数可见,换句话说,及时我们仅仅是用声明友元的类的成员调用该友元函数,它也必须是被声明过的。
struct X {
friend void f() {/*友元函数可以定义在类的内部*/}
X() { f(); } //错误:f()还没有被声明
void g();
void h();
};
void X::g() { return f();} //错误:f()还没有被声明
void f(); //声明那个定义在X中的函数
void X::h() { return f(); } //正确:现在f的什么在作用域中了