C++Primer_Chap07_类_List03_类的其他特性_笔记

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的什么在作用域中了

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值