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

实际编程中有时会碰到两个类之间交叉引用的问题,比如一个类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;

};

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的接口将同时作用于类A
class 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()
{
	......
}
时间: 2024-10-13 19:33:29

两个C++类的交叉引用和同步改变的相关文章

交叉引用的解决方法——类声明的应用

交叉引用的解决方法 什么是交叉引用? 什么是交叉引用?一言以蔽之,就是:A类中包含B类的对象,B类中包含A类的对象. 以一场景为例 我们先来看一个场景.假设有一个电子文档(Document).一个文档下有多个页(Page),每个页下有多个文本单元(TextUnit,表示文档内元素的基本单位),一个文档中的所有文本单元对象都有唯一的ID.这样每创建一个文本单元时都要为其设置一个唯一的ID,我们在Document类中就需要一个生成唯一ID的方法为所有的文本单元创建唯一标识.于是我们就会有下面的类关系

【转】 C++中两个类相互包含引用问题

原文:http://blog.csdn.net/leo115/article/details/7395077 在构造自己的类时,有可能会碰到两个类之间的相互引用问题,例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型 class A { int i; B b; } class B { int i; A* a; } 请注意上面的定义内容,一般情况下是不能出现类A,类B相互引用都定义对象,即如下的样子: class A { int i; B b; } class B { int

C++两个类相互包含引用的问题

在构造自己的类时,有可能会碰到两个类之间的相互引用问题,例如:定义了类A类B,A中使用了B定义的类型,B中也使用了A定义的类型 class A { B b; } class B { A* a; } 请注意上面的定义内容,一般情况下是不能出现类A,类B相互引用都定义对象,即如下的样子: class A { B b; } class B { A a; } 编译器在声明A的时候,由于B的声明在A的下面所以出现编译错误 那么,在定义时因为相互引用肯定会需要相互包含头文件,如果仅仅只是在各自的头文件中包含

多态时最好将基类的析构函数设为virtual、 C++中两个类相互包含引用问题 (转载)

多态:http://blog.csdn.net/tmljs1988/article/details/8146521 C++中两个类相互包含引用问题:http://blog.csdn.net/leo115/article/details/7395077 http://blog.csdn.net/tmljs1988/article/details/6081132

两个类相互包含引用的问题--类前向声明

1.背景 编程中遇到如下错误:使用不完全类型**以及**前向声明. 查找相关资料后发现是类的前向声明(forward declaration)问题:在程序中声明一个类后,此类是一个不完全类型(incompete type),即已知此类是一个类型,但不知道包含哪些成员. 不完全类型只能以有限方式使用,不能定义该类型的对象.不完全类型只能用于定义指向该类型的指针及引用,或者用于声明(而不是定义)使用该类型作为形参类型或返回类型的函数. 2.为什么需要前向声明 在构造自己的类时,有可能会碰到两个类之间

Python模块的交叉引用问题分析

实际项目中遇到python模块相互引用问题,查资料,说是通过import局部导入的方式可以避免错误,资料如附录所述. 但更改后测试还是会出错,很疑惑!? 如果哪位读者有好的解决方法,敬请留言说明,谢谢. 所以,最好的方法是不进行交叉引用,如果需要就单独分一个模块出来. 附录:Python模块的交叉引用问题解读:How can I have modules that mutually import each other? 有下面两个文件相互引用,Python解释器报错. foo.py: from

spring容器注入一个接口的两个实现类

spring容器中能拥有两个同种类型的bean吗?我有两个dao类同时实现一个接口,这两个接口注入时报了异常如下. Text代码   org.springframework.beans.factory.NoSuchBeanDefinitionException: No unique bean of type [com.xxx.xxx.xxx.integration.dao.IDAO] is defined: expected single matching bean but found 2: [

基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针

您查询的关键词是:c++primer习题15.25 以下是该网页在北京时间 2016年07月15日 02:57:08 的快照: 如果打开速度慢,可以尝试快速版:如果想更新或删除快照,可以投诉快照. 百度和网页 http://bbs.csdn.net/topics/380238133 的作者无关,不对其内容负责.百度快照谨为网络故障时之索引,不代表被搜索网站的即时页面. 首页 精选版块 移动开发 iOS Android Qt WP 云计算 IaaS Pass/SaaS 分布式计算/Hadoop J

Word交叉引用

第一种:参考文献,用NE插入. 第二种:交叉引用. 先定义新的编号格式[1](主要解决参考文献格式自动编号的问题),感觉但是没有解决缩进的问题,需要Tab. 但是实验发现,通过谷歌学术引用的参考文献插在这类标号后边自动缩进了,如上图:然后在需要的地方