C++学习笔记一 —— 两个类文件互相引用的处理情况
先记录一些零碎的知识点:
1. 一个类可以被声明多次,但只能定义一次,也就是可以 class B; class B; class B; ……; class B {……}; 这样子。
2. 一个类 C 的声明中(函数只声明还没定义)可以使用一个只被声明还没定义的类 B,但只能使用类 B 的指针或引用(用作函数参数或其他等等),不能是完整的对象。
3. 若类 C 的函数中需要使用到类 B 的函数,则类 B 的函数必须已定义好而不能只是声明。
- #include<iostream>
- class B;
- class B;
- class B;
- class C;
- class C;
- class B {
- public:
- void func() const { std::cout << "B.func()" << std::endl; }
- void func(C *c) const; // { /* c->func(); */ }
- // 无法在这里直接使用 c->func();如果强迫在同一个文件中实现的话代码结构会变得很乱
- };
- class C {
- public:
- C() {}
- void func() const {
- std::cout << "C.func():" << std::endl;
- }
- void func(B *b) const {
- std::cout << "C.func(B *b):" << std::endl;
- b->func();
- }
- void func(const B *b) const { // 底层 const 可以重载,顶层 const 不可以重载
- std::cout << "C.func(const B *b):" << std::endl;
- b->func();
- }
- void func(const B &b) const {
- std::cout << "C.func2(const B &b):" << std::endl;
- b.func();
- }
- };
- void B::func(C *c) const {
- std::cout << "B.func(C *c):" << std::endl;
- c->func();
- }
- int main() {
- C c;
- B b;
- b.func(&c);
- const B cb;
- c.func(&b);
- c.func(&cb);
- c.func(b);
- std::endl(std::cout);
- return ;
- }
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; ,也就是为要引用的类作声明,所以两个头文件如下:
- class C;
- class B {
- public:
- void func() const { std::cout << "B.func()" << std::endl; }
- void func(C *c) const;
- };
B.h
- class B;
- class C {
- public:
- C() {}
- void func() const { std::cout << "C.func():" << std::endl; }
- void func(B *b) const ;
- void func(const B *b) const ;
- void func(const B &b) const ;
- };
C.h
相应的 .cpp 文件如下:
- void B::func(C *c) const {
- std::cout << "B.func(C *c):" << std::endl;
- c->func();
- }
B.cpp
- void C::func(B *b) const {
- std::cout << "C.func(B *b):" << std::endl;
- b->func();
- }
- void C::func(const B *b) const { // 底层 const 可以重载,顶层 const 不可以重载
- std::cout << "C.func(const B *b):" << std::endl;
- b->func();
- }
- void C::func(const B &b) const {
- std::cout << "C.func2(const B &b):" << std::endl;
- b.func();
- }
C.cpp
然后在主函数中,除了 #include "B.h" 和 #include "C.h" 外,还要依次 #include "B.cpp" 和 #include "C.cpp" :
- #include<iostream>
- #include "B.h"
- #include "C.h"
- #include "B.cpp"
- #include "C.cpp"
- int main() {
- C c;
- B b;
- b.func(&c);
- const B cb;
- c.func(&b);
- c.func(&cb);
- c.func(b);
- std::endl(std::cout);
- return ;
- }
main.cpp
注意,必须先 #include 完所有的 .h 头文件才可以 #include *.cpp 文件,否则编译会报错,这是因为 *.cpp 里的都是实现,必须确实地得到相应的类或函数的定义才行,所以必须先把所有的 .h 头文件也就是所有的声明引入才可以,编译器才能按照其规则生成中间代码和进行函数的链接。(好像 cocos2d-x 中也是这样子的?)
可以看到,分解后的代码结构更清晰更容易维护,否则只能像第一个 main.cpp 文件一样糅合在一起,当类的数量和规模增多时难以维护。
C++ primer ch13 中的 Message 和 Folder 类稍后再整理,休息下准备上课了。
C++学习笔记一 —— 两个类文件互相引用的处理情况的更多相关文章
- Java NIO 学习笔记(六)----异步文件通道 AsynchronousFileChannel
目录: Java NIO 学习笔记(一)----概述,Channel/Buffer Java NIO 学习笔记(二)----聚集和分散,通道到通道 Java NIO 学习笔记(三)----Select ...
- JVM学习笔记-第六章-类文件结构
JVM学习笔记-第六章-类文件结构 6.3 Class类文件的结构 本章中,笔者只是通俗地将任意一个有效的类或接口锁应当满足的格式称为"Class文件格式",实际上它完全不需要以磁 ...
- Protocol Buffer学习教程之编译器与类文件(三)
Protocol Buffer学习教程之编译器与类文件(三) 1. 概述 在前面两篇中,介绍了Protobuf的基本概念.应用场景.与protobuf的语法等.在此篇中将介绍如何自己编译protobu ...
- AJPFX学习笔记JavaAPI之String类
学习笔记JavaAPI之String类 [size=10.5000pt]一.所属包java.lang.String,没有子类.特点:一旦被初始化就不可以被改变. 创建类对象的两种方式: String ...
- 并发编程学习笔记(10)----并发工具类CyclicBarrier、Semaphore和Exchanger类的使用和原理
在jdk中,为并发编程提供了CyclicBarrier(栅栏),CountDownLatch(闭锁),Semaphore(信号量),Exchanger(数据交换)等工具类,我们在前面的学习中已经学习并 ...
- java学习笔记07--日期操作类
java学习笔记07--日期操作类 一.Date类 在java.util包中定义了Date类,Date类本身使用非常简单,直接输出其实例化对象即可. public class T { public ...
- Java程序猿的JavaScript学习笔记(10—— jQuery-在“类”层面扩展)
计划按例如以下顺序完毕这篇笔记: Java程序猿的JavaScript学习笔记(1--理念) Java程序猿的JavaScript学习笔记(2--属性复制和继承) Java程序猿的JavaScript ...
- 多态时最好将基类的析构函数设为virtual、 C++中两个类相互包含引用问题 (转载)
多态:http://blog.csdn.net/tmljs1988/article/details/8146521 C++中两个类相互包含引用问题:http://blog.csdn.net/leo11 ...
- java学习笔记16--I/O流和文件
本文地址:http://www.cnblogs.com/archimedes/p/java-study-note16.html,转载请注明源地址. IO(Input Output)流 IO流用来处理 ...
随机推荐
- C++程序设计(三)
1. 运算符重载 目的:对抽象数据类型也能够直接使用C++提供的运算符.使得程序更简洁,代码更容易理解. 运算符重载的实质是函数重载 返回值类型 operator 运算符(形参表) { -- } 运算 ...
- Android-Activity使用(2) -传值
一.简单传值 1.修改MainActivity protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedIns ...
- mysql 三种恢复方式
为了保障数据的安全,需要定期对数据进行备份.备份的方式有很多种,效果也不一样.一旦数据库中的数据出现了错误,就需要使用备份好的数据进行还原恢复.从而将损失降到最低.下面我们来了解一下MySQL常见的有 ...
- Docker的私有仓库
server 192.168.1.107 registry ---push client 192.168.1.103 --pull [192.168.1.107 ...
- lua MVC框架 Orbit初探
介绍 http://keplerproject.github.io/orbit/ Orbit是lua语言版本的MVC框架. 此框架完全抛弃CGILUA的脚本模型, 支持的应用, 每个应用可以卸载一个单 ...
- .Net分布式架构(一):Nginx实现负载均衡
一:负载均衡简介 负载均衡,英文名称为Load Balance,其意思就是分摊到多个操作单元上进行执行,例如Web服务器.FTP服务器.企业关键应用服务器和其它关键任务服务器等,从而共同完成工作任务. ...
- db2实例、数据库、表空间
创建数据数据库之前必须创建实例,数据库是运行在实例之上的.实例在本质上是由一些后台进程和共享内存组成.实例相当于是数据库的一个容器,可以包含多个数据库,但是一个数据库只能由一个实例进行管理.相当于Wi ...
- java 静态函数锁对象说明
在内存加载.class文件后,会自动创建一个对象,用于保存class的信息,与我们程序员手工创建的对象不一样.
- XML标签
SQL标签库提供了创建和操作XML文档的标签. 引入语法:<%@ taglib prefix="x" uri="http://java.sun.com/jsp/js ...
- 如何在Macbook Pro搭建PHP开发环境
[Apache] sudo apachectl start // 启动Apache服务 sudo apachectl restart // 重启Apache服务 sudo apachectl s ...