In this case, Box need access to Cup.func, AND Cup need access to Box.func, both of which are private because I don't want any other class to have access to neither Box.func nor Cup.func.

So they need to declare each other as friend.

Suppose you organise code like Box1.h, Box1.cpp, Cup1.h, Cup1.cpp, it would cause a problem like this: http://www.cnblogs.com/qrlozte/p/4099032.html

The compiler will complain. So the solution is also simple, see Cup2.h, Cup2.cpp, other files remain unchanged. (Of couse, you can change Box1.h Box1.cpp using the same pattern as Cup2.h Cup2.cpp, although it would make your code looks more consistent, but only changing Cup1.h, Cup1.cpp is already enough to satisfy your need.)

Another question, what if Box.doSomething is a function template? If you change main1.cpp to main2.cpp, and Box1.h, Box1.cpp to Box2.h, Box2.cpp, the linker will complain that it cannot find the implementation of Box.doSomething (undefined reference error) (after all, the compiler need all the detail of a template to generate code, if you hide the implementation of Box.doSomething in Box2.cpp, how can you expect the compiler can generate code for Box.doSomething<int>() in main2.cpp when main2.cpp doesn't include Box2.cpp, right?).

So, because function template (and class template) must define (just declare is NOT enough) in the header, you might modify Box2.h and Box2.cpp as shown in Box3.h and Box3.cpp. And you'll find the problem is solved! (Now we got main2.cpp, Box3.h, Box3.cpp, Cup2.h, Cup2.cpp compiled successfully).

Now consider what if Cup.doSomething also need to be a function template? (The same as Box.doSomething in Box3.h). And... yes, you have to include the definition of Cup.doSomething in Cup.h, too!

And you if you that, the compiler will complain Box is an incomplete type thus in Cup.doSomething, "b.func" cannot be resolved. As shown in main3.cpp, Cup3.h, Cup3.cpp.

The reason is because in Cup3.h "class Box;" it indeed declares class Box, but just the class name, no information is provided about the interface of the class at all.

Can you replace "class Box;" with "#include "Box.h"" ? No. Because that'll cause the same problem as Box1.h, Box1.cpp, Cup1.h, Cup1.cpp caused.

The solution ? At least for now, I don't know(If I can seperate Cup.doSomething() into two parts, one part is template and one part is normal function and the template part doesn't have to access memebers of the parameter 'b', then there's a simple solution, just let the template part in the header, and implement the normal function in Cup.cpp). This situation is not made up by me, I really encountered this problem when I was making a little program. Maybe there's something wrong with my design.

main1.cpp

 #include "Box.h"
#include "Cup.h" int main()
{
Cup c;
Box b;
c.doSomething(b);
b.doSomething(c);
return ;
}

Box1.h

 #ifndef BOX_H
#define BOX_H #include "Cup.h" class Box
{
friend class Cup;
public:
Box();
~Box();
void doSomething(const Cup &c);
private:
void func() const;// only visible to Cup
}; #endif // BOX_H

Box1.cpp

 #include "Box.h"

 #include <iostream>

 Box::Box()
{ }
Box::~Box()
{ }
void Box::doSomething(const Cup &c)
{
c.func();
}
void Box::func() const
{
using namespace std;
cout << "Box.func" << endl;
}

Cup1.h

 #ifndef CUP_H
#define CUP_H #include "Box.h" class Cup
{
friend class Box;
public:
Cup();
~Cup();
void doSomething(const Box &b);
private:
void func() const; // only visible to Box
}; #endif // CUP_H

Cup1.cpp

 #include "Cup.h"

 #include <iostream>

 Cup::Cup()
{ }
Cup::~Cup()
{ }
void Cup::doSomething(const Box &b)
{
b.func();
} void Cup::func() const
{
using namespace std;
cout << "Cup.func" << endl;
}

Cup2.h

 #ifndef CUP_H
#define CUP_H class Box;

class Cup
{
friend class Box;
public:
Cup();
~Cup();
void doSomething(const Box &b);
private:
void func() const; // only visible to Box
}; #endif // CUP_H

Cup2.cpp

 #include "Cup.h"

 #include "Box.h"

 #include <iostream>

 Cup::Cup()
{ }
Cup::~Cup()
{ }
void Cup::doSomething(const Box &b)
{
b.func();
} void Cup::func() const
{
using namespace std;
cout << "Cup.func" << endl;
}

main2.cpp

 #include "Box.h"
#include "Cup.h" int main()
{
Cup c;
Box b;
c.doSomething(b);
b.doSomething<int>(, c);
return ;
}

Box2.h

#ifndef BOX_H
#define BOX_H #include "Cup.h" class Box
{
friend class Cup;
public:
Box();
~Box();
template <typename T> void doSomething(const T &obj, const Cup &c);
private:
void func() const;// only visible to Cup
}; #endif // BOX_H

Box2.cpp

 #include "Box.h"

 #include <iostream>

 Box::Box()
{ }
Box::~Box()
{ }
template <typename T> void doSomething(const T &obj, const Cup &c)
{
c.func();
}
void Box::func() const
{
using namespace std;
cout << "Box.func" << endl;
}

Box3.h

 #ifndef BOX_H
#define BOX_H #include "Cup.h" class Box
{
friend class Cup;
public:
Box();
~Box();
template <typename T> void doSomething(const T &obj, const Cup &c);
private:
void func() const;// only visible to Cup
}; template <typename T> void Box::doSomething(const T &obj, const Cup &c)
{
c.func();
} #endif // BOX_H

Box3.cpp

 #include "Box.h"

 #include <iostream>

 Box::Box()
{ }
Box::~Box()
{ } void Box::func() const
{
using namespace std;
cout << "Box.func" << endl;
}

main3.cpp

 #include "Box.h"
#include "Cup.h" int main()
{
Cup c;
Box b;
c.doSomething<int>(, b);
b.doSomething<int>(, c);
return ;
}

Cup3.h

 #ifndef CUP_H
#define CUP_H class Box; class Cup
{
friend class Box;
public:
Cup();
~Cup();
template <typename T> void doSomething(const T &obj, const Box &b);
private:
void func() const; // only visible to Box
}; template <typename T> void doSomething(const T &obj, const Box &b)
{
b.func();
} #endif // CUP_H

Cup3.cpp

 #include "Cup.h"

 #include "Box.h"

 #include <iostream>

 Cup::Cup()
{ }
Cup::~Cup()
{ } void Cup::func() const
{
using namespace std;
cout << "Cup.func" << endl;
}

c++ two classes as each others' friends的更多相关文章

  1. 代码的坏味道(9)——异曲同工的类(Alternative Classes with Different Interfaces)

    坏味道--异曲同工的类(Alternative Classes with Different Interfaces) 特征 两个类中有着不同的函数,却在做着同一件事. 问题原因 这种情况往往是因为:创 ...

  2. eclipse中的classes文件夹同步问题

    问题: 在同步项目时,由于误操作将classes文件夹加入到了同步版本中,这样会导致每次更新程序编译后,会有很多class文件显示在同步清单中. 解决方案: 将classes文件不设置为同步. 1. ...

  3. Introduction of OpenCascade Foundation Classes

    Introduction of OpenCascade Foundation Classes Open CASCADE基础类简介 eryar@163.com 一.简介 1. 基础类概述 Foundat ...

  4. 6.Configure Domain Classes(配置领域类)【EF Code-First 系列】

    在前面的部分中,我们学习了Code-First默认约定,Code-First使用默认的约定,根据你的领域类,然后生成概念模型. Code-First模式,发起了一种编程模式:约定大于配置.这也就是说, ...

  5. app:clean classes Exception

    Error:Execution failed for task ':app:clean'.> Unable to delete directory: C:\Users\LiuZhen\Deskt ...

  6. Android framework编译出来的jar包classes.jar的位置

    在源码环境下编译 Android framework编译出来的jar包classes.jar的位置  out/target/common/obj/JAVA_LIBRARIES/framework_in ...

  7. yii 核心类classes.php详解(持续更新中...)

    classes.php在yii运行的时候将被自动加载,位于yii2文件夹底下. <?php /** * Yii core class map. * * This file is automati ...

  8. Top 15 Java Utility Classes

    In Java, a utility class is a class that defines a set of methods that perform common functions. Thi ...

  9. Eclipse下无法自动编译,或者WEB-INF/classes目录下没文件,编译失败的解决办法(转载)

    文章来源:http://www.cnblogs.com/xfiver/archive/2010/07/07/1772764.html 1.  IOException parsing XML docum ...

  10. [Android] 升级了新的android studio之后 发生如下的报错,The following classes could not be instantiated:

    The following classes could not be instantiated:- android.support.v4.widget.DrawerLayout (Open Class ...

随机推荐

  1. Delphi 7生成XML

    文件格式为: Day 制1課 U12 ASSY01 Wrist 1009 0 2018/05/18 09:35:59 Day 制1課 U12 ASSY02 Wrist 1010 0 2018/05/1 ...

  2. 扩展gridview轻松实现冻结行和列(增强型)

    上一篇说过,还可以扩展gridview的分页功能以及实现导出结果为EXCEL/PDF的功能.实现好后应该封装起来,以方便后续的项目简单使用.至于要如何实现,我想不必过多的说了.下面是显示结果和主要的代 ...

  3. Android集成友盟社会化分享功能

    1.  产品概述 友盟社会化组件,可以让移动应用快速具备社会化分享.登录.评论.喜欢等功能,并提供实时.全面的社会化数据统计分析服务. 指南将会手把手教你使用社会化组件SDK,用5分钟为APP增加新浪 ...

  4. tengine + lua 实现流量拷贝

    环境搭建参考地址:http://www.cnblogs.com/cp-miao/p/7505910.html cp.lua local res1, res2, action action = ngx. ...

  5. 通过API获取 Portus+registry docker仓库信息

    接口获取docker centos 镜像的 tag 列表脚本 # -*- encoding:utf-8 -*- import requests import json ""&quo ...

  6. windows server 2012将计算机图标添加到桌面(图文教程)(转)

    windows server 2012系统安装完以后桌面默认只有回收站一个图标,如何将window常用的图标(计算机.控制面板.网络.用户文件)的图标添加到桌面呢,下面为作者本人亲测.操作简单至极. ...

  7. JS组件系列——显示隐藏密码切换的jQuery插件

    <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="utf-8& ...

  8. scrapy-splash抓取动态数据例子十三

    一.介绍 本例子用scrapy-splash通过搜狗搜索引擎,输入给定关键字抓取微信资讯信息. 给定关键字:数字:融合:电视 抓取信息内如下: 1.资讯标题 2.资讯链接 3.资讯时间 4.资讯来源 ...

  9. oneapm的技术博客(简书),用来追溯群里的讨论,mark

    http://www.jianshu.com/users/572133740c3f/latest_articles

  10. C# 鼠标全局钩子

    /// <summary> /// 鼠标全局钩子 /// </summary> public class MouseHook { private const int WM_MO ...