实际编程中有时会碰到两个类之间交叉引用的问题,比如一个类A含一个类B的指针成员,一个类B含类A的指针成员,两个类相互“关联”;而且更重要的是:对类B的任意修改应该同时改变A中的B指针指向的值,同理适用于类A。良好的设计应当可以通过任意一个类的接口来同时改变A、B两个对象,而不必调用两个类的对应接口。
boost::enable_shared_from_this提供了这个能力
代码:
A.h:
#pragma once
#include <boost/shared_ptr.hpp>
class CB;
typedef boost::shared_ptr<CB> B_ptr;
class CA
{
friend class CB; // 为了调用SetB函数
public:
CA(int i):m_aInt(i){}
B_ptr GetB(){ return m_bObj; }
void SetI(int i){ m_aInt = i; }
int GetI(){ return m_aInt; }
private:
// 为了防止此接口误用,让其为private
// 改变关联时应通过B的接口,否则造成"a关联了b,但b没有关联a"
void SetB(B_ptr pb) { m_bObj = pb; } // 这个函数只在B中关联时被调用
int m_aInt;
B_ptr m_bObj;
};
typedef boost::shared_ptr<CA> A_ptr;
B.h:
#pragma once
#include <boost/enable_shared_from_this.hpp>
#include "A.h"
// 类B在概念上包含类A,通过类B的接口将同时作用于类A
class CB: public boost::enable_shared_from_this<CB>
{
public:
CB(int i):m_bInt(i){}
// CB(int i, A_ptr pa):m_bInt(i){ Connect(pa); } // error! B类还没有构造完毕,就使用shared_from_this()
void Connect(A_ptr pa); // 关联
void Disconnect(); // 取消关联
A_ptr GetA(){ return m_aObj; }
void SetI(int i){ m_bInt = i; }
int GetI(){ return m_bInt; }
private:
int m_bInt;
A_ptr m_aObj;
};#include "B.h"
void CB::Connect(A_ptr pa)
{
m_aObj = pa; // B有一个A成员
pa->SetB(shared_from_this()); // B本身现在是A的成员
}
void CB::Disconnect()
{
if(m_aObj)
{
m_aObj->SetB(B_ptr()); // A中的B成员为空
m_aObj = A_ptr(); // B中的A成员为空
}
}#include <iostream>
#include "B.h"
void PrintInfo(A_ptr aObj, B_ptr bObj)
{
std::cout << "============info============" << std::endl;
std::cout << "a_i: " << aObj->GetI() << std::endl;
std::cout << "a_b_i: " << aObj->GetB()->GetI() << std::endl;
std::cout << "b_a_i: " << bObj->GetA()->GetI() << std::endl;
std::cout << "b_i: " << bObj->GetI() << std::endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
A_ptr aObj(new CA(1)); // A中的B成员是空的
B_ptr bObj(new CB(9)); // B中的A成员是空的
bObj->Connect(aObj); // 建立关联
// aObj->SetB(bObj); // error! 此句不能替代上一句
PrintInfo(aObj, bObj);
aObj->SetI(11);
PrintInfo(aObj, bObj);
bObj->SetI(99);
PrintInfo(aObj, bObj);
aObj->GetB()->SetI(22);
PrintInfo(aObj, bObj);
bObj->GetA()->SetI(33);
PrintInfo(aObj, bObj);
// 改变B关联的A对象
A_ptr aObj2(new CA(2));
bObj->Disconnect(); // 释放原来的关联,A中的B成员现在是空
bObj->Connect(aObj2); // 建立新的关联
PrintInfo(aObj2, bObj);
// aObj->GetB()->GetI(); // error! aObj没有与B关联
return 0;
}类B中的Connect方法用于A、B对象的相互关联,在此之前先构造A、B的一个对象,A、B中的指针对象全部采用智能指针。
关联之后,可以通过A、B的任一方法同时改变关联的数据:如aObj->SetI(11);同时改变a中int和b关联的a的int
类B的Disconnect取消两者的关联,同步改变机制就不存在了,并且A中的B成员和B中的A成员都为空,除非重新Connect。
注意:在Connect之前,A、B的各自构造函数不包含智能指针成员的初始化,shared_from_this()必须在一个类构造完成之后再调用,所以在类B构造函数中调用Connect是一种错误,类A中的SetB函数单向地使一个B与其关联,这个函数只被Connect和Disconnect调用,为防止误用,设为private,则B是A的友元
一种优化可以是:只将Connect和Disconnect设为类A的友元,防止类B的其他成员函数对它的误用
这样修改:
A.h:
#pragma once
#include "B.h"
class CA
{
friend void CB::Connect(A_ptr pa); // 为了调用SetB函数
friend void CB::Disconnect(); // 为了调用SetB函数
.....
}#include <boost/shared_ptr.hpp>
#include <boost/enable_shared_from_this.hpp>
class CA;
typedef boost::shared_ptr<CA> A_ptr;
// 类B在概念上包含类A,通过类B的接口将同时作用于类A
class CB: public boost::enable_shared_from_this<CB>
{
.....
};
typedef boost::shared_ptr<CB> B_ptr;#include "A.h"
// A的成员函数定义在此
// A的友元函数(B的两个成员函数)定义在此
void CB::Connect(A_ptr pa)
{
.....
}
void CB::Disconnect()
{
......
}原文地址:http://blog.csdn.net/u013470115/article/details/44306355