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为0
StrBlobPtr(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;//定义一个空的weakptr
size_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为0
StrBlobPtr(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;//定义一个空的weakptr
size_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;
}
可以得到: