zoukankan      html  css  js  c++  java
  • C++学习笔记一 —— 两个类文件互相引用的处理情况

      先记录一些零碎的知识点:

    1. 一个类可以被声明多次,但只能定义一次,也就是可以 class B;  class B;  class B; ……;  class B {……};  这样子。

    2. 一个类 C 的声明中(函数只声明还没定义)可以使用一个只被声明还没定义的类 B,但只能使用类 B 的指针或引用(用作函数参数或其他等等),不能是完整的对象。

    3. 若类 C 的函数中需要使用到类 B 的函数,则类 B 的函数必须已定义好而不能只是声明。

     1 #include<iostream>
     2 
     3 class B;
     4 class B;
     5 class B;
     6 
     7 class C;
     8 class C;
     9 
    10 class B {
    11 public:
    12     void func() const {   std::cout << "B.func()" << std::endl;   }
    13     void func(C *c) const;  //  {  /* c->func(); */  }
    14     // 无法在这里直接使用 c->func();如果强迫在同一个文件中实现的话代码结构会变得很乱
    15 };
    16 
    17 class C {
    18 public:
    19     C() {}
    20     void func() const {
    21         std::cout << "C.func():" << std::endl;
    22     }
    23     void func(B *b) const {
    24         std::cout << "C.func(B *b):" << std::endl;
    25         b->func();
    26     }
    27     void func(const B *b) const {       // 底层 const 可以重载,顶层 const 不可以重载
    28         std::cout << "C.func(const B *b):" << std::endl;
    29         b->func();
    30     }
    31     void func(const B &b) const {
    32         std::cout << "C.func2(const B &b):" << std::endl;
    33         b.func();
    34     }
    35 };
    36 
    37 
    38 void B::func(C *c) const {
    39     std::cout << "B.func(C *c):" << std::endl;
    40     c->func();
    41 }
    42 
    43 
    44 int main() {
    45     C c;
    46     B b;
    47     b.func(&c);
    48     const B cb;
    49 
    50     c.func(&b);
    51     c.func(&cb);
    52     c.func(b);
    53     std::endl(std::cout);
    54     return 0;
    55 }
    main.cpp

      因此,鉴于以上的种种规则,对于两个互相依赖难以分割的类,我们可以用一些比较规范的方法去组织项目的结构,比如对于两个类 B 和 C:

    1. 在 B.h 和 C.h 两个头文件中分别声明好 class B {……} 和 class C {……} ,类内需要引用到另一个类的函数只有声明而暂时没有定义,而把这些函数的定义也就是实现全部写到 B.cpp 和 C.cpp 中(或者把所有函数的定义都放到 .cpp 文件中去);

    2. 在 B.h 头文件的顶端写上 class C; ,在 C.h 头文件的顶端写上 class B; ,也就是为要引用的类作声明,所以两个头文件如下:

    1 class C;
    2 
    3 class B {
    4 public:
    5     void func() const {   std::cout << "B.func()" << std::endl;   }
    6     void func(C *c) const;
    7 };
    B.h

      

     1 class B;
     2 
     3 class C {
     4 public:
     5     C() {}
     6     void func() const  {   std::cout << "C.func():" << std::endl;   }
     7     void func(B *b) const ;
     8     void func(const B *b) const ;
     9     void func(const B &b) const ;
    10 };
    C.h

      相应的 .cpp 文件如下:

    1 void B::func(C *c) const {
    2     std::cout << "B.func(C *c):" << std::endl;
    3     c->func();
    4 }
    B.cpp
     1 void C::func(B *b) const {
     2     std::cout << "C.func(B *b):" << std::endl;
     3     b->func();
     4 }
     5 
     6 void C::func(const B *b) const {       // 底层 const 可以重载,顶层 const 不可以重载
     7     std::cout << "C.func(const B *b):" << std::endl;
     8     b->func();
     9 }
    10 
    11 void C::func(const B &b) const {
    12     std::cout << "C.func2(const B &b):" << std::endl;
    13     b.func();
    14 }
    C.cpp

      然后在主函数中,除了 #include "B.h" 和 #include "C.h" 外,还要依次 #include "B.cpp" 和 #include "C.cpp" :

     1 #include<iostream>
     2 #include "B.h"
     3 #include "C.h"
     4 #include "B.cpp"
     5 #include "C.cpp"
     6 
     7 int main() {
     8     C c;
     9     B b;
    10     b.func(&c);
    11     const B cb;
    12 
    13     c.func(&b);
    14     c.func(&cb);
    15     c.func(b);
    16     std::endl(std::cout);
    17     return 0;
    18 }
    main.cpp

      注意,必须先 #include 完所有的 .h 头文件才可以 #include *.cpp 文件,否则编译会报错,这是因为 *.cpp 里的都是实现,必须确实地得到相应的类或函数的定义才行,所以必须先把所有的 .h 头文件也就是所有的声明引入才可以,编译器才能按照其规则生成中间代码和进行函数的链接。(好像 cocos2d-x 中也是这样子的?)

      可以看到,分解后的代码结构更清晰更容易维护,否则只能像第一个 main.cpp 文件一样糅合在一起,当类的数量和规模增多时难以维护。

      C++ primer ch13 中的 Message 和 Folder 类稍后再整理,休息下准备上课了。

  • 相关阅读:
    Leetcode143. Reorder List重排链表
    Leetcode93. Restore IP Addresses复原IP地址
    Leetcode92. Reverse Linked List II反转链表
    Leetcode970. Powerful Integers强整数
    Leetcode931. Minimum Falling Path Sum下降路径最小和
    2019个人计划与Flag与期望
    排查问题-查看日志的正确打开方式
    Vuex-状态管理模式
    Git 常用操作(二)
    Hive:HQL和Mysql:SQL 的区别
  • 原文地址:https://www.cnblogs.com/Newdawn/p/4994357.html
Copyright © 2011-2022 走看看