c++ two classes as each others' friends

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

 1 #include "Box.h"
 2 #include "Cup.h"
 3
 4 int main()
 5 {
 6     Cup c;
 7     Box b;
 8     c.doSomething(b);
 9     b.doSomething(c);
10     return 0;
11 }

Box1.h

 1 #ifndef BOX_H
 2 #define BOX_H
 3
 4 #include "Cup.h"
 5
 6 class Box
 7 {
 8     friend class Cup;
 9     public:
10         Box();
11         ~Box();
12         void doSomething(const Cup &c);
13     private:
14         void func() const;// only visible to Cup
15 };
16
17 #endif // BOX_H

Box1.cpp

 1 #include "Box.h"
 2
 3 #include <iostream>
 4
 5 Box::Box()
 6 {
 7
 8 }
 9 Box::~Box()
10 {
11
12 }
13 void Box::doSomething(const Cup &c)
14 {
15     c.func();
16 }
17 void Box::func() const
18 {
19     using namespace std;
20     cout << "Box.func" << endl;
21 }

Cup1.h

 1 #ifndef CUP_H
 2 #define CUP_H
 3
 4 #include "Box.h"
 5
 6 class Cup
 7 {
 8     friend class Box;
 9     public:
10         Cup();
11         ~Cup();
12         void doSomething(const Box &b);
13     private:
14         void func() const; // only visible to Box
15 };
16
17 #endif // CUP_H

Cup1.cpp

 1 #include "Cup.h"
 2
 3 #include <iostream>
 4
 5 Cup::Cup()
 6 {
 7
 8 }
 9 Cup::~Cup()
10 {
11
12 }
13 void Cup::doSomething(const Box &b)
14 {
15     b.func();
16 }
17
18 void Cup::func() const
19 {
20     using namespace std;
21     cout << "Cup.func" << endl;
22 }

Cup2.h

 1 #ifndef CUP_H
 2 #define CUP_H
 3
 4 class Box;
 5
 6 class Cup
 7 {
 8     friend class Box;
 9     public:
10         Cup();
11         ~Cup();
12         void doSomething(const Box &b);
13     private:
14         void func() const; // only visible to Box
15 };
16
17 #endif // CUP_H

Cup2.cpp

 1 #include "Cup.h"
 2
 3 #include "Box.h"
 4
 5 #include <iostream>
 6
 7 Cup::Cup()
 8 {
 9
10 }
11 Cup::~Cup()
12 {
13
14 }
15 void Cup::doSomething(const Box &b)
16 {
17     b.func();
18 }
19
20 void Cup::func() const
21 {
22     using namespace std;
23     cout << "Cup.func" << endl;
24 }

main2.cpp

 1 #include "Box.h"
 2 #include "Cup.h"
 3
 4 int main()
 5 {
 6     Cup c;
 7     Box b;
 8     c.doSomething(b);
 9     b.doSomething<int>(1, c);
10     return 0;
11 }

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

 1 #include "Box.h"
 2
 3 #include <iostream>
 4
 5 Box::Box()
 6 {
 7
 8 }
 9 Box::~Box()
10 {
11
12 }
13 template <typename T> void doSomething(const T &obj, const Cup &c)
14 {
15     c.func();
16 }
17 void Box::func() const
18 {
19     using namespace std;
20     cout << "Box.func" << endl;
21 }

Box3.h

 1 #ifndef BOX_H
 2 #define BOX_H
 3
 4 #include "Cup.h"
 5
 6 class Box
 7 {
 8     friend class Cup;
 9     public:
10         Box();
11         ~Box();
12         template <typename T> void doSomething(const T &obj, const Cup &c);
13     private:
14         void func() const;// only visible to Cup
15 };
16
17 template <typename T> void Box::doSomething(const T &obj, const Cup &c)
18 {
19     c.func();
20 }
21
22 #endif // BOX_H

Box3.cpp

 1 #include "Box.h"
 2
 3 #include <iostream>
 4
 5 Box::Box()
 6 {
 7
 8 }
 9 Box::~Box()
10 {
11
12 }
13
14 void Box::func() const
15 {
16     using namespace std;
17     cout << "Box.func" << endl;
18 }

main3.cpp

 1 #include "Box.h"
 2 #include "Cup.h"
 3
 4 int main()
 5 {
 6     Cup c;
 7     Box b;
 8     c.doSomething<int>(1, b);
 9     b.doSomething<int>(1, c);
10     return 0;
11 }

Cup3.h

 1 #ifndef CUP_H
 2 #define CUP_H
 3
 4 class Box;
 5
 6 class Cup
 7 {
 8     friend class Box;
 9     public:
10         Cup();
11         ~Cup();
12         template <typename T> void doSomething(const T &obj, const Box &b);
13     private:
14         void func() const; // only visible to Box
15 };
16
17 template <typename T> void doSomething(const T &obj, const Box &b)
18 {
19     b.func();
20 }
21
22 #endif // CUP_H

Cup3.cpp

 1 #include "Cup.h"
 2
 3 #include "Box.h"
 4
 5 #include <iostream>
 6
 7 Cup::Cup()
 8 {
 9
10 }
11 Cup::~Cup()
12 {
13
14 }
15
16 void Cup::func() const
17 {
18     using namespace std;
19     cout << "Cup.func" << endl;
20 }

c++ two classes as each others' friends

时间: 2024-10-15 07:02:47

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

【Scala】Scala之Classes and Properties

一.前言 前面学习了控制结构,下面学习Scala的Class和Properties. 二.Class&Properties 尽管Scala和Java很类似,但是对类的定义.类构造函数.字段可见性控制等则不相同,Java更为冗长,Scala精炼.本章将通过Scala的构造函数工作原理来理解Scala的类和字段,当申明类构造函数参数和使用var.val.private关键字来修饰类的字段时,Scala编译器将会为你生成代码,根据字段修饰符不同,Scala编译器会生成不同的存取函数,本章也会展示如何重

Delphi使用普通类对象创建接受window消息(使用Classes.AllocateHWnd为对象创建一个尺寸为0的窗口,从而有了Handle)good

在delphi中,有时候我们希望对象可以接收windows消息,怎么办呢?因为要接收windows消息起码要有windows Handle,难道要建立的一个可见窗口?那样似乎太差强人意了.delphi提供了一个函数Classes.AllocateHWnd.分析AllocateHWND发现delphi CreateWindowEx一个尺寸为0的窗口,窗口是生成了,Handle也有了,但窗口的消息要处理吧,否则怎么说让对象接收Windows消息呢,但我们都知道类函数和Windows消息处理函数是不一

&lt;Python&gt; Classes

Classes Python classes provide all the standard features of Object Oriented Programming: the class inheritance mechanism allows multiple base classes, a derived class can override any methods of its base class or classes, and a method can call the me

[翻译]The Neophyte&#39;s Guide to Scala Part 12: Type Classes

The Neophyte's Guide to Scala Part 12: Type Classes 过去的两周我们讨论了一些使我们保持DRY和灵活性的函数式编程技术,特别是函数组合,partial function的应用,以及currying.接下来,我将会继续讨论如何使你的代码尽可能的灵活. 但是,这次我们将不会讨论怎么使用函数作为一等对象来达到这个目的,而是使用类型系统,这次它不是阻碍着我们,而是使得我们的代码更灵活:你将会学到关于 type classes 的知识. 你可能会觉得这是一

Machine learning system design---Error metrics for skewed(偏斜的) classes

skewed classes skewed classes: 一种类里面的数量远远高于(或低于)另一个类,即两个极端的情况. 预测cancer的分类模型,如果在test set上只有1%的分类误差的话,乍一看是一个很好的结果,实际上如果我们将所有的y都预测为0的话(即都不为cancer),分类误差为0.5%(因为cancer的比率为0.5%).error降低了,那这是对算法的一种改进吗?显然不是的.因为后面一种方法实际上什么也没有做(将所有的y=0),不是一种好的机器学习算法.所以这种error

tomcat工程项目classes下无dao工程的xml文件

tomcat在部署maven的web项目时,所关联的dao工程没有部署到E:\apache-tomcat-6.0.41\webapps\vehicleserv\WEB-INF\classes下(即这里面没有dao工程里的xml文件),导致tomcat启动时报找不到dao工程中的配置文件(如<import resource="classpath:applicationContext-dao.xml" /><import resource="classpath:

Structs vs classes(值类型vs引用类型)

我们知道classes是引用类型,structs属于值类型.这就意味着,当你传递一个class,Swift传递的是对象的引用,而当你传递一个struct,Swift传递的是对象的值. 在playground写下如下代码,看看它的输出及其效果. Structs vs classes 上面分别定义了一个结构体一个类,它们都只有一个变量.代码分别生成一个struct和class,并保存它们至相应的变量中,然后分别赋值它们至第二个变量,最后代码改变了第二个变量的属性. 我们可以发现,在struct示例中

Java - Nested Classes

(本文参考:http://docs.oracle.com/javase/tutorial/java/javaOO/nested.html) Nested Classes class OuterClass { ...... class StaticNestedClass { ...... } ...... class InnerClass { ...... } 定义 nested classes (嵌套类)分为两种:non-static与static,前者通常称作inner classes,后者称

(转)8 Tactics to Combat Imbalanced Classes in Your Machine Learning Dataset

8 Tactics to Combat Imbalanced Classes in Your Machine Learning Dataset by Jason Brownlee on August 19, 2015 in Machine Learning Process Has this happened to you? You are working on your dataset. You create a classification model and get 90% accuracy

(转) Learning from Imbalanced Classes

Learning from Imbalanced Classes AUGUST 25TH, 2016 If you’re fresh from a machine learning course, chances are most of the datasets you used were fairly easy. Among other things, when you built classifiers, the example classes werebalanced, meaning t