c++ Primer 5 12.1.6节练习 (头文件相互包含的问题及解决办法)
来源:互联网 发布:mysql update 索引 编辑:程序博客网 时间:2024/06/14 13:05
12.19
拿此题来说,StrBlobPtr类要用到StrBlob类,而StrBlob类要用到StrBlobPtr类。
即如下:
class StrBlob{friend class StrBlobPtr;public:typedef std::vector<std::string>::size_type size_type;StrBlob();//默认构造函数StrBlob(std::initializer_list<std::string>);//接收1个参数的initializer_list作为形参size_type size() const { return data->size(); }bool empty() const { return data->empty(); }void push_back(const std::string &t) { return data->push_back(t); }void pop_back();std::string& front();std::string& back();StrBlobPtr begin() { return StrBlobPtr(*this); }//返回一个指向首元素的迭代器StrBlobPtr end(){ auto ret = StrBlobPtr(*this, this->size()); return ret; }//返回尾后的迭代器private:std::shared_ptr<std::vector<std::string>> data;//一个指向vector<string>的智能指针void check(size_type i, const std::string &msg) const;//检查data[i]是否合法,抛出异常};
class StrBlobPtr{public:StrBlobPtr() :curr(0) { }//默认构造函数,令curr为0StrBlobPtr(StrBlob &a, size_t t = 0) :wptr(a.data), curr(t) { }//带参数的构造函数string & deref() const;//解引用操作StrBlobPtr & incr();//递增操作private:shared_ptr<vector<string>> check(size_t, const string&) const;//检查下标是否过界weak_ptr<vector<string>> wptr;//定义一个空的weakptrsize_t curr;//定义元素下标};
可以看到这两个类要相互包含,那么该怎样处理?
1.如果两个都在各自的.h中,并且相互包含对方的.h,不用前置声明。
即在StrBlob.h文件中 #include "StrBlobPtr.h" 在StrBlobPtr.h文件中 #include "StrBlob.h"
在main.cpp中 #include "StrBlob.h" ,会出现什么样的错误呢?
error C2027: 使用了未定义类型“StrBlobPtr”,即该类未定义。
因为在头文件中使用了保护符,那么编译器只对每个头文件编译一次,那么在StrBlob.h中就不再编译StrBlobPtr类,即StrBlob使用的是未定义的类。
2.如果对1进行前置声明 ,为了清晰明了,用类A和B表示。
#pragma once #include "B.h" class B; class A { public: B* b; }; //文件B.h中的代码 #pragma once #include "A.h" class B; class B { public: A* a; };这样,我们发现编译成功。即说明了,头文件不能替代前置声明。
但我们将各自对方的头文件去掉,再次编译,发现仍然编译成功。那么什么时候该包含对方的.h文件呢?
3.包含对方.h头文件的原则。
/***********************************此段来自网络*********************************/
头文件包含其实是一想很烦琐的工作,不但我们看着累,编译器编译的时候也很累,再加上头文件中常常出现的宏定义。感觉各种宏定义的展开是非常耗时间的,远不如自定义函数来得速度。这里仅就不同头文件、源文件间的句则结构问题提出两点原则,仅供参考:
第一个原则应该是,如果可以不包含头文件,那就不要包含了。这时候前置声明可以解决问题。如果使用的仅仅是一个类的指针,没有使用这个类的具体对象(非指针),也没有访问到类的具体成员,那么前置声明就可以了。因为指针这一数据类型的大小是特定的,编译器可以获知。
第二个原则应该是,尽量在CPP文件中包含头文件,而非在头文件中。假设类A的一个成员是是一个指向类B的指针,在类A的头文件中使用了类B的前置声明并编译成功,那么在A的实现中我们需要访问B的具体成员,因此需要包含头文件,那么我们应该在类A的实现部分(CPP文件)包含类B的头文件而非声明部分(H文件)。
/****************************************************************************************/
当我们的类只用到另一个类的的指针,引用等,没有去使用这个类的实例和他的具体成员,我们就直接使用前置声明,无需在自己的头文件.h中去包含对方的的.h,包含对方的.h可以放在自己的.cpp文件中去。
4.如果我们必须要使用另一个类的具体实例,或者成员函数。该怎么做?
一、使用全局变量+extern声明。
但实际上这样也破坏封装性。
二、使用基类指针。
...............之后复习基类在补充。
三、将两个类写在一个.h文件中,不要忘记前置声明。
按此题为例:
class StrBlobPtr;class StrBlob{friend class StrBlobPtr;public:typedef vector<string>::size_type size_type;StrBlob();//默认构造函数StrBlob(initializer_list<string>);//接收1个参数的initializer_list作为形参size_type size() const { return data->size(); }bool empty() const { return data->empty(); }void push_back(const string &t) { return data->push_back(t); }void pop_back();string& front();string& back();//StrBlobPtr begin() { return StrBlobPtr(*this); }//返回一个指向首元素的迭代器//StrBlobPtr end(){ auto ret = StrBlobPtr(*this, this->size()); return ret; }//返回尾后的迭代器StrBlobPtr begin();//注意,这两个函数必须在类StrBlobPtr定义后,才能定义,因为它使用了StrBlobPtr的具体实例StrBlobPtr end();private:shared_ptr<vector<string>> data;//一个指向vector<string>的智能指针void check(size_type i, const string &msg) const;//检查data[i]是否合法,抛出异常};class StrBlobPtr{public:StrBlobPtr() :curr(0) { }//默认构造函数,令curr为0StrBlobPtr(StrBlob &a, size_t t = 0) :wptr(a.data), curr(t) { }//带参数的构造函数string & deref() const;//解引用操作StrBlobPtr & incr();//递增操作private:shared_ptr<vector<string>> check(size_t, const string&) const;//检查下标是否过界weak_ptr<vector<string>> wptr;//定义一个空的weakptrsize_t curr;//定义元素下标};
然后在.cpp中定义各个函数即可。
值得注意的是,写在一个.h文件中时,前置声明之后,那个类是不完全的类,我们同样只能使用他的指针或者引用等,如红色的两行只能先声明,在StrBlobPtr定义之后在定义。
四、如果用到对方类,只用其类的指针或者引用,然后在自己的.h里前置声明对方类,不用包含对方的.h,在自己的.cpp实现时,再包含对方的.h
如下:
StrBlob.h中:
#ifndef STRBLOB_H_#define STRBLOB_H_#include <iostream>#include <vector>#include <initializer_list>#include <memory>#include <stdexcept>using namespace std;class StrBlobPtr;class StrBlob{
StrBlob.cpp中
#include "StrBlob.h"#include "StrBlobPtr.h"
StrBlobPtr.h中
#ifndef STRBLOBPTR_H_#define STRBLOBPTR_H_#include <iostream>#include <vector>#include <initializer_list>#include <memory>#include <stdexcept>using namespace std;class StrBlob;class StrBlobPtr{
StrBlobPtr.cpp中
#include "StrBlobPtr.h"#include "StrBlob.h"
这样,程序可以正常编译。
12.20
#include <iostream>#include <fstream>#include <string>#include <vector>#include "StrBlob.h"#include "StrBlobPtr.h"using namespace std;int main(){ ifstream input("F:\\test\\input.txt"); string temp; StrBlob sb; if (getline(input, temp)) { sb.push_back(temp); while (getline(input, temp)) { sb.push_back(temp); } } else cerr << "No data!" << endl; for (auto i = sb.begin(); neq(i, sb.end()); i.incr()) //neq即!= ,incr()即++i cout << i.deref() << endl; system("pause"); return 0;}
可以得到:
- c++ Primer 5 12.1.6节练习 (头文件相互包含的问题及解决办法)
- C头文件相互包含的问题
- C/C++ 中头文件相互包含引发的问题
- C/C++ 中头文件相互包含引发的问题
- C/C++ 中头文件相互包含引发的问题
- 解决C/C++ 头文件相互包含 问题的方法
- C/C++ 中头文件相互包含引发的问题
- C/C++ 中头文件相互包含引发的问题
- 解决C/C++ 头文件相互包含 问题的方法
- C/C++ 中头文件相互包含引发的问题
- 解决C/C++ 头文件相互包含 问题的方法
- C/C++ 中头文件相互包含引发的问题
- C/C++ 中头文件相互包含引发的问题
- 头文件相互包含的问题
- 头文件相互包含的问题
- 两个头文件相互包含的问题
- C++头文件相互包含的问题
- 头文件相互包含的问题
- yii框架学习经历-6.4数据库迁移
- Excel身份证提取户籍所在省份地区:Excel函数不求人
- vue之组件的生命周期
- 链表Java实现
- Linux
- c++ Primer 5 12.1.6节练习 (头文件相互包含的问题及解决办法)
- Unity3D Shader之路 写Shader前必须要知道的事情3 ShaderForge的简单使用
- Android butterknife简单使用篇
- JNI
- 内讧!迅雷大数据公司股权被内部人於菲窃取,并报案!
- ES6 你可能不知道的事
- Zookeeper(单机版)搭建
- wav文件格式分析详解
- CodeIgniter源码阅读笔记(1)——框架入口index.php