最简单的例子,用A初始化B,用B初始化A
打算用A的m_a变量初始化 B的m_b,以及用B的m_b初始化 m_a. 先将m_a和m_b设置为public,否则不能直接访问别的类的私有成员。
做法:
- 声明A
class A;
- 完成B的函数书写,但是用到A的函数还不能写出函数实体,只能声明。需要在A完成之后再进行函数实体的书写
- 完成A的class实现,这里面可以将用到B的函数写出实现过程,因为B已经实现过了。
- 将B中用到A的函数实现出来。
#include <iostream>
class A; //必须要写这个声明,之后再去实现
class B
{
public:
B():m_b(0){}
B(A& a); //这里也只是声明,因为还不知道A的内容,所以在这里不能完成函数的实现
int m_b; //这里先设置成 public,否则A不能完成使用m_b来初始化自己
};
class A
{
public:
A():m_a(0){}
A(B& b):m_a(b.m_b){} //
int m_a;
};
int main()
{
return 0;
}
B::B(A& a)
{
m_b = a.m_a;
}
正常情况下A的m_a, B的m_b应该是私有成员,那么就需要借助友元类来完成这个功能。也就是在A里面声明 friend class B。这样B能用A的私有成员。 同时在B的内部声明 friend class A,这样A能用B的私有成员。
代码如下:
#include <iostream>
class A;
class B
{
public:
B():m_b(0){}
B(A& a);
friend class A;
private:
int m_b;
};
class A
{
public:
A():m_a(0){}
A(B& b):m_a(b.m_b){}
friend class B;
private:
int m_a;
};
B::B(A& a)
{
m_b = a.m_a;
}
int main()
{
return 0;
}
在KartoSLAM 和ORB代码中,还有一些这样的用法:A的成员 有B的指针m_pB,B的成员有A的指针m_pA。
同时希望能够达到这样的效果:以Karto SLAM中的 Mapper、ScanMatcher为例, Mapper的一个指针pMapper和pMapper->m_pSequentialScanMatcher->m_pMapper指向同一个地址。
下面代码是一个简单的描述两个类之间关系的代码
class Mapper
{
public:
friend class ScanMatcher;
private:
ScanMatcher* m_pSequentialScanMatcher;
}
class ScanMatcher
{
private:
Mapper* m_pMapper;
}
接下来要如何实现这么一个功能:(由于类内有指针,因此这里还需要写出合适的析构函数)
#include <iostream>
//先写出 MapperGraph和ScanMatcher,这个先写后写和实现函数有关
class Mapper;
class ScanMatcher
{
public:
//本身ScanMatcher其实是有m_pMapper这个指针的,但是因为m_pMapper很重要,
//不能在释放ScanMatcher的时候删除m_pMapper。
//virtual 只是为了给 继承类 重写覆盖用的,在这里不关键
//override 用在子类中,其实没什么大作用,是为了保证被这个关键词修饰的函数是被
//写成virtual的。加入override可以保证不会因为书写错误而导致编译通过,
//但实际功能没有达到预期的效果
virtual ~ScanMatcher(){};
public:
static ScanMatcher* Create(Mapper* pMapper);
protected:
ScanMatcher(Mapper* pMapper):m_pMapper(pMapper){}
private:
Mapper* m_pMapper;
};
class Mapper
{
friend class ScanMatcher;
public:
Mapper();
~Mapper()
{
delete m_pSequentialScanMatcher;
m_pSequentialScanMatcher = NULL;
}
public:
void Initialize();
private:
ScanMatcher* m_pSequentialScanMatcher;
};
Mapper::Mapper():m_pSequentialScanMatcher(NULL){}
void Mapper::Initialize()
{
m_pSequentialScanMatcher = ScanMatcher::Create(this);
}
ScanMatcher* ScanMatcher::Create(Mapper* pMapper)
{
ScanMatcher* pScanMatcher = new ScanMatcher(pMapper);
return pScanMatcher;
}
int main()
{
Mapper* pMapper = new Mapper();
pMapper->Initialize();
return 0;
}
这样就完成上面的功能了。