1、友元(friend)
类可以允许其他类或者函数访问它的非公有成员,方法是令其他类或者函数成为它的友元。
增加一条以friend关键字开始的函数声明语句即可:
一般来说最好在类定义开始或者结束的位置集中声明友元
友元的声明仅仅指定了访问权限,而非一个通常意义上的函数声明。
关键概念
封装的好处:
确保用户代码不会在无意间破坏封装对象的状态
被封装的类的具体实现细节可以在随时改变,而无需调整用户级别的代码。
2、类的其他特性
类的成员、类成员的初始值、可变数据成员、内联成员函数、从成员函数返回*this
2.1
定义一个类性成员
类可以自定义某种类型在类中的别名。由类定义的类型名字和其他成员一样存在访问限制,可以是public或者private的一种。
class A{
public:
typedef std::string::size_type pos;
//使用类型别名等价的声明一个类型的名字
using pos = std::string::size_type;
private:
pos height = 0;
}
2.2
可变数据成员
有时我们希望能修改类的某个数据成员,即使是一个const成员函数内。可以通过在变量的声明中加入mutable关键字做到这一点。
一个可变数据成员(mutable data member)永远不会是const,即使它是对const对象的成员。
class Screen{
public:
void some_member() const;
private:
mutalbe size_t access_ctr;//即使在一个const对象内也可以被修改
};
void Screen::some_member() const
{
++access_ctr; //保存一个计数值,用于记录成员函数被调用的次数。
}
2.3
类数据成员的初始值
2.4
返回*this的成员函数
class Screen{
public:
Screen &set(char);
Screen &set(pos,pos,char);
inline Screen &Screen::set(char c)
{
contents[cursor] = c;
return *this; //将this对象作为左值返回
//返回的是对象本身为非对象的副本
}
从const成员函数返回*this
一个const成员函数如果以引用的形式返回*this,那么它的返回类型是常量引用。
2.5
类类型
我们可以把类名作为类型名字使用,从而直接指向类类型。或者,我们也可以把类名跟在关键字class或struct后面
class A{
};
A item1;
class A item1; //一条等价的声明
类的声明
类的声明和定义也可以分开
class A; //前向声明(forward declaration)
//在定义之前它是一个不完全类型(incomplete type)
不完全类型只能在非常有限的情景下使用:可以定义指向该类型的指针或引用,也可以声明以不完全类作为参数或者返回类型的函数。(但不能定义)
对一个类来说,在创建他它的对象之前该类必须被定义过,而不能仅仅被声明过。否则编译器就无法了解这样的对象需要多少存储空间。
2.6
友元
类可以把非成员函数定义为友元, 也可以把其他类定义为友元,也可以把其他类的成员函数定义为友元。
class Screen{
friend class Window_mgr;
}
友元关系不存才传递性。,每个类负责控制自己的友元类或者友元函数。
令成员函数成为友元
class Screen{
friend void Window_mgr::clear(ScreenIndex);
};
3、
类的作用域
在类的作用域之外,普通的数据和函数成员只能由对象、引用或者指针使用成员访问运算符来访问。
对于类型成员则使用作用域运算符访问。
4、
构造函数
构造函数初始化列表与赋值的区别
成员函数初始化列表初始化顺序与它们在类中的声明顺序一致
委托构造函数
委托构造函数(delegating constructor)。一个委托构造函数使用它所属类的其他构造函数执行它自己的初始化过程,或者说它把自己的一些或者全部职责委托给了其他构造函数
class Sales_data{
public:
//非委托构造函数,使用实参初始化成员
Sales_data(std::string s, unsigned cnt, double price):
bookNo(s), units_sold(cnt), revenue(cnt*price){}
//委托构造函数
Sales_data():Sales_data("",0,0){}
Sales_data(std::string s):Sales_data(s,0,0){}
Sales_data(std::istream &is):Sales_data()
{
read(is,*this);
}
//当受委托的构造函数执行完成后,执行函数体中的内容。
};
5、
聚合类
聚合类(aggregate class)是的用户可以直接访问其成员,并且具有特殊的初始化语法形式。当一个类满足如下条件时,我们说它是聚合的:
- 所有成员都是public的
- 没有定义任何构造函数
- 没有类内初始值
- 没有基类,也没有virtual函数
我们可以提供一个用花括号括起来的初始值列表,来初始化聚合类的数据成员。顺序与声明顺序一致。
6、类的静态成员
一般来说,我们不能在类的内部初始化静态成员。相反的,必须在类的外部定义和初始化每个静态成员。
类似于全局变量,静态数据成员定义在任何函数之外。
静态成员可以是不完全类型
class Bar{
public:
//...
private:
static Bar mem1;
Bar *mem2;
Bar mem3;//
}