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流用来处理 ...
随机推荐
- 64位win10系统无法安装.Net framework3.5的解决方法
前言 Win10不会自带安装.net framework 3.5,而很多软件必须基于.net framework 3.5 sp1(例如:Sql Server 2014),从官网上下载的.net fra ...
- android NumberPicker 数组越界的坑
被这个问题耽误了一个多小时... 直接上解决方案,参考红色部分. private void initViews() { wheel = (NumberPicker) findViewById(R.id ...
- Avada主题通过自定义CSS全局更换微软雅黑字体
Avada主题的菜单.正文.标题.面包屑路径等等如果想更换为“微软雅黑”中文字体,只需要进入Avada主题的选项,倒数第二项有个Custom CSS,把下面的代码粘贴进去即可.当然你也可以自行改变字体 ...
- 检测中文长度gbk下2个字节
//$str = 'fff&sdf你是sdf好fdf啊b歌hello中world';$str = 'd你b_fff是好啊歌中潺潺 ';echo chineselength($str).&quo ...
- 关于SqlParameter设定size和value
1.设定size 字段定义:column [Text] nvarchar(max) NULL 设定字段最大长度: new SqlParameter("@Text",SqlDbTyp ...
- Eclipse中为自己写完的函数添加注释(快捷键ALT+SHIFT+J)
函数名上右键:Source--->Generate Element Comment
- hibernate中load和get方法的区别
1.读取时机不同(当lazy=true的时候) load是采用延迟机制(load语句不读库,等使用非主键时才去读库),而get不采用延 迟机制(get语句时马上读库): 2.搜索不到数据时的情 ...
- jquery mobile界面数据刷新
JQM里面当我们更新了某些页面标签(如: listview, radiobuttons, checkboxes, select menus)里的数据时,必须做refresh操作. 为什么必须做refr ...
- 【final】站立会议---11.28
名称:nice! 组长:李权 成员:韩媛媛 刘芳芳 宫丽君 于淼 项目名称:约跑app 时间:11月28日 12:30 内容: 新任务的分配 1.李权分配任务 2.韩媛媛写站立会议 3.刘芳芳修改BU ...
- AppleWatch___学习笔记(一)开发思路和框架
一.开发须知 如果你没有开发过 iphone,直接来做watch,我建议你不要这么做,不是不可以,而是目前所有的第三方应用都必须基于iphone的扩展,原生的watch应用,苹果目前还没有开放给开发者 ...