C++类:类类型、友元再探(友元类 与 其他类的成员函数做友元)

类类型

​ 每个类都定义了唯一的类型。对于两个类来说,即使它们的成员完全一样,这两个类也是不同的类型。

struct First {
    int memi;
    int getmemi();
};
struct Second {
    int memi;
    int getmemi();
};
First obj1;
Second obj2 = obj1;			// 错误:obj1 和 obj1 的类型不同

​ 可以把类名作为类型的名字使用,从而直接指向类类型。当然,也可以跟在 struct 或者 class 后面。

Sales_data item1;			// 默认初始化 Sales_data 类型的对象
class Sales_data item1;		// 一条等价的声明

类的声明

  • 类也可以进行声明。在它声明之后定义之前是一个不完全类型,此时已知该类是一个类类型,但是并不知道它包含哪些成员。

  • 不完全类型的使用有限:可以定义指向这种类型的引用或指针,也可以声明(不能定义)以不完全类型作为参数或者返回类型的函数。

  • 对于一个类来说,如果要创建它的对象,那么该类必须在此对象之前就被定义过,只仅仅声明是不够的。只有声明的话,编译器是无法了解该对象需要的空间的。同理,定义后才能用引用或者指针访问其成员,当然可以用更加简单的道理来讲,没有定义就不知道含有的成员有哪些,何来的访问成员。

  • !!注意:类只有在全部完成后才算被定义,所以类的成员类型不能该类自己,但是类中允许包含指向它自身的引用或指针,因为定义类时,类的名字出现后,就被认为声明过了。

  class Link_Screen {
      Screen window;
      Link_Screen *Next;
      Link_Screen *Prev;
  };

友元再探

​ 类除了可以把普通的非常成员函数定义为友元。类还可以把其他类定义成友元,也可以把其他类(之前已定义的)的成员函数定义成友元。此外,友元函数能定义在类的内部,这样的函数是隐式内联的。

类之间的友元关系

​ 举一个友元类的例子。我们的 Window_mgr 类的某些成员可能需要访问它管理的 Screen 类的内部数据。例如,假设我们需要为 Window_mgr 添加一个名为 clear 的成员,它负责把一个指定的 Screen 的内容都设为空白。显然,clear 需要访问 Screen 的私有成员;但是想令这种访问合法,Screen 需要把 Window_mgr 指定为它的友元。

class Screen {
    // Window_mgr 的成员可以访问 Screen 类的私有部分
    friend class Window_mgr;
    // Screen 类的剩余部分
};

​如果一个类指定了友元类,则友元类的成员函数可以访问次类包括非公有成员在内的所有成员。

所以Screen 类将 Window_mgr 声明为友元类后, clear 函数便可以这样:

class Window_mgr {
public:
    // 窗口中的每个屏幕编号
    using ScreenIndex = std::vector<Screen>::size_type;
    void clear(ScreenIndex);
private:
    std::vector<Screen> Screens{Screen(24,80,' ')};
};

void Window_mgr::clear(ScreenIndex i) {
    // s 是一个 Screen 的引用,指向我们想清空的屏幕
    Screen &s = Screens[i];
    // 置为空白
    s.contents = string(s.height * s.width,' ');
}

注意:友元关系不存在传递性。即,如果 Window_mgr 有它自己的友元,这些友元并不能访问 Screen。每个类负责控制自己的友元类或友元函数>

令成员函数作为友元

​ 除了令整个 Window_mgr 作为友元之外,Screen 类可以只为 clear 提供访问权限。

class Screen {
    // Window_mgr::clear 必须在 Screen 类之前被声明
    friend void Window_mgr::clear(ScreenIndex);
    // Screen 的剩余部分
};

​ 如果你有亲自上手敲过这些出现的代码,你会发现 令成员函数作为友元 对组织程序的结构以及一些必要的声明十分重要。这里按照如果方式设计程序:

  • 首先定义 Window_mgr 类,其中声明 clear 函数,但是不定义。在 clear 使用 Screen 的成员之前必须先声明 Screen
  • 接下来定义 Screen,包括对 clear 的友元声明
  • 最后定义 clear,此时它才可以使用 Screen 的成员

如果按照 C++ primer 中出现的顺序敲上的代码,会出现一定的问题。这里的问题见博客:C++ primer 练习 7.3.4 https://blog.csdn.net/no_O_ac/article/details/104248485

函数重载与友元

​ 虽然重载函数的名字相同,但是仍然是不同的函数。与普通函数一样,如果一个类想把重载函数声明为它的友元,仍需要声明具体。并不是声明一个函数为友元,此类重载函数都是友元。

友元声明和作用域

​ 类和非成员函数的声明不是必须在它们的友元声明之前。当一个名字第一次出现在一个友元声明中时,我们隐式地假定该名字在当前作用域是可见的。然而,友元本身不一定真的就声明在当前作用域。

注意:友元声明影响的是访问权限,并非普通意义上的函数声明。就算是友元函数定义在了类的内部

struct X {
    friend void f() { /* 友元函数可以定义在类的内部*/ }
    X() { f(); }			// 错误,f 还没有被声明
    void g();
    void h();
};
void X::g() { return f(); }		// 错误,f 还没有被声明
void f();
void X::h() { return f(); }		// 正确,现在 f 的声明在作用域中
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值