友元和前向声明

typedef的作用域

typedef也有作用域,如果其在类内定义,在外部访问时要加上上class_name:: 而且要受到类的访问控制符的限制。

前向声明

 class Screen;

这样的声明被称为前向声明,它向程序中引入了名字Screen并指明它是一种类类型。在它声明之后,定义之前是一种不完全类型(编译器并不清楚它的内部结构)因此,不完全类型只可以在有限的情况下使用。

  • 可以定义指向该类型的引用或指针

  • 可以声明(但是不能定义)以不完全类型作为参数或者返回值的函数。

什么时候使用前向说明

当两个类存在相互依赖关系时,可以使用前向说明。例如:两个类A与B是强耦合关系,类A要引用B的对象,类B也要引用类A的对象

 //A.h
 class B;
 class A{
 private:
     B* b = NULL;
 public:
     A();
     xxx(B&);
 };
 ​
 //B.h
 class A;
 class B{
 private:
     A *a;
 public:
     B()=default;
     xxx(A &);
 };
 ​
 //A.cpp
 #include "A.h"
 #include "B.h"
 A::A(){ b = new B; }
 A::xxx(B&){....}
 ​
 //B.cpp
 #include "A.h"
 #include "B.h"
 B::B(){ a = new A; }
 B::xxx(A&){....}
 ​

友元

友元的作用及分类

类可以允许其他类或者函数访问它的非公有成员。这就是友元的作用。友元包含:友元非成员函数、友元类、友元成员函数 友元函数只是对权限的声明,所以它不受访问权限符的限制,可以放在类的任意位置。一般在类的开头或者结尾统一声明

友元非成员函数

如果类想把一个非成员函数声明为友元函数。只有要在类内以friend开头声明即可。注意:友元的声明仅仅指定了访问的权限,他并不是一个常规的函数声明。所以对于非成员函数来说,在其被使用之前,最好在类外部再次声明该函数。所以,通常将该函数的声明和包含友元声明的类的声明一起放在头文件中去使用,这样可以保证正确性。

友元类

如果一个类指定了友元类,则友元类的所有成员函数都可以访问此类的所有成员。友元类的声明有两种方式:

  • 如果声明友元类的类要使用该类的指针或者用作函数形参,可以使用前向声明

 class Screen;
 class Windows_mgr{
 friend Screen;
 private:
     Screen *sc;
 .....
 };
  • 如果只是单纯声明,可以直接使用:

 class Windows_mgr{
 friend class Screen;
 };

其中,第二种方式适合任意的情况,第一种也可以使用第二种的声明方式

友元成员函数

当一个类要把另一个类的成员函数声明为友元时,它必须了解要声明的那个类的内部结构。也就是说:被声明友元的类必须要在声明友元的类之前声明。因此,必须按照合理的顺序去组织代码。 一般情况下,友元函数一般也要使用声明友元的类作为参数。这也就构成了一种相互依赖的关系。所以要使用前向声明。

例如:Screen要声明windows_mgr类的clear函数为友元函数。clear函数要以screen的引用为参数。那么代码的组织方式如下:

  • 首先要在windows_mgr头文件中声明windows_mgr类,在其中声明clear函数,又因为clear要使用screen,所以对Screen进行前向声明;

  • 接着,在Screen头文件中,include windows_mgr头文件,以保证Screen可以了解windows的内部结构。接着声明Screen类,在其内部声明clear的友元。

  • 在windows的cpp文件中,include screen头文件,此时的cpp就包含了所有需要的类的信息,然后就可以实际定义clear函数。

 //Windows_mgr.h
 #include 
 class Screen;
 class Windows_mgr
 {
     typedef std::vector::size_type ScreenIndex;
 ​
 private:
     std::vector screens;
 ​
 public:
     Windows_mgr() = default;
     void add_screen(Screen *myscreen) { screens.push_back(myscreen); }
     void clear(ScreenIndex);
 };
 ​
 //Screen.h
 #include "Windows_mgr.h"
 #include 
 #include 
 class Screen
 {
     friend void Windows_mgr::clear(ScreenIndex);
     typedef std::string::size_type pos;
 ​
 private:
     pos cursor = 0, height = 0, width = 0;
     std::string contents;
     void do_display(std::ostream &os) const { os << contents; }
 ​
 public:
     Screen() = default;
     Screen(pos he, pos wi) : height(he), width(wi), contents(he * wi, ' ') {}
     Screen(pos he, pos wi, char c) : height(he), width(wi), contents(he * wi, c) {}
     Screen &move(pos x, pos y)
     {
         cursor = x * width + y;
         return *this;
     }
     Screen &set(char c)
     {
         contents[cursor] = c;
         return *this;
     }
 ​
     Screen &display(std::ostream &os)
     {
         do_display(os);
         return *this;
     }
 ​
     //基于const的重载
     const Screen &display(std::ostream &os) const
     {
         do_display(os);
         return *this;
     }
 };
 //Windows_mgr.cc
 #include "Screen.h"
 ​
 void Windows_mgr::clear(ScreenIndex index)
 {
     Screen *s = screens[index];
     s->contents = std::string(s->height * s->width, ' ');
 }
 ​
 int main()
 {
     Screen myScreen(5, 5, 'X');
     myScreen.display(std::cout);
     std::cout << std::endl;
     Windows_mgr mgr;
     mgr.add_screen(&myScreen);
     mgr.clear(0);
     myScreen.display(std::cout);
 }

你可能感兴趣的:(C++,note,c++)