两个C++类的交叉引用和同步改变

来源:互联网 发布:类似爱投顾的软件 编辑:程序博客网 时间:2024/05/21 20:27

实际编程中有时会碰到两个类之间交叉引用的问题,比如一个类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中关联时被调用intm_aInt;B_ptrm_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的接口将同时作用于类Aclass 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:intm_bInt;A_ptrm_aObj;};

B.cpp:

#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成员为空}}

main.cpp:

#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函数.....}

B.h:

#include <boost/shared_ptr.hpp>#include <boost/enable_shared_from_this.hpp>class CA;typedef boost::shared_ptr<CA> A_ptr;// 类B在概念上包含类A,通过类B的接口将同时作用于类Aclass CB: public boost::enable_shared_from_this<CB>{   .....};typedef boost::shared_ptr<CB> B_ptr;

A.cpp: 将B的成员Connect和Disconnect从B.cpp中移入

#include "A.h"// A的成员函数定义在此// A的友元函数(B的两个成员函数)定义在此void CB::Connect(A_ptr pa){ .....}void CB::Disconnect(){......}

0 0
原创粉丝点击