假设有两个类 A 和 B:
class A {};
class B {};
下面的两个例子在哪些方面有所不同?
示例 1:
class C : public A, public B {};
示例 2:
class C
{
//private
friend class A;
friend class B;
}
假设有两个类 A 和 B:
class A {};
class B {};
下面的两个例子在哪些方面有所不同?
示例 1:
class C : public A, public B {};
示例 2:
class C
{
//private
friend class A;
friend class B;
}
Afriend
可以触摸private
任何它是朋友的部分(双关语只是稍微有意!;)),但没有任何东西是A
它B
的一部分C
- 它只是意味着“A
并且B
可以触摸C
's private bits”)。任何“小于”private
的东西当然也可用于A
and B
,因此如果C
有protected
orpublic
成员,它也将可用。
当您继承时,A
andB
成为C
. 和的任何private
部分均不可用于。在“is-a”与“has-a”的命名法中,现在 is-a和 is-a - 换句话说,它是从 继承的,所以它“表现得像从界面的角度来看。A
B
C
C
A
B
A
A
有几个很大的不同。继承和友谊是非常不同的。
有了友谊,C 类不是A 类或 B 类的实例。因此,如果你有这样的函数:
void processMyClass(A* a);
您不能将 C 的实例传递给它,而如果 C 子类 A(公开),它就是A 的实例。
有了友谊,A 类和 B 类可以接触 C 的所有私有成员数据和功能。有了继承,C 类可以接触 A 和 B 的公共和受保护成员。
友谊不是遗传的。这意味着,例如:
class D : public C
{
private:
void foo() {
// A and B cannot call this function
}
}
在您使用的上下文中,为了尽我所能回答您的问题,朋友们只需允许您的类共享受保护/私有数据,而继承也会这样做,除了会有更深层次的关系,其中类是相同的(例如与铸造)。
虽然您得到的答案相当准确,但我认为它们并不完整。特别是,尽管它们解释了友谊和继承之间的区别,但并没有真正解释什么时候应该使用哪个,或者区别如何影响您的代码。
继承(在 C++ 中)的主要用途是在基类中定义接口,并在多个派生类中的每一个中实现该接口。派生类必须实现的接口部分通常由基类中的纯虚函数表示。
Ship 在 C++ 中的主要用途friend
是定义构成接口一部分的东西,但由于语法原因不能成为成员函数。一个非常常见的示例是流插入或提取运算符。要将这些实现为成员函数,它们必须是流类的成员。由于我们不想不断地修改流类,因此它们是自由函数,它们将对流的引用作为其左参数,并将对它们插入/提取的类型的(可能是 const)对象的引用作为它们的右操作数。
这些不一定必须是friend
类的 s - 它们可以被编写为仅使用类的公共接口。但是,如果您这样做,则通常意味着该类在其公共接口中公开的内容比其他必要的要多。界面不再是最小的,这往往表明设计存在问题。
不过需要注意的是:您可以在类定义中定义一个友元函数:
class Foo {
// ...
friend std::ostream &operator<<(std::ostream &os, Foo const &f) {
// ...
}
};
起初,这可能看起来很奇怪(从语法上讲,有点奇怪)。即使它是在类定义中定义的,friend
也意味着这不是成员函数。至少在我看来,这相当准确地反映了它的情况:从概念上讲,它是类的一部分。它可以访问私有成员,就像类的任何其他成员一样。它是一个自由函数而不是成员函数这一事实纯粹是一个实现工件,与代码的设计基本上没有任何关系。
这也指出了传送和继承之间的另一个区别friend
:对于继承,您通常主要处理成员函数。每个成员函数仍然接收一个this
指针,因此每个成员函数都直接与类的特定实例相关联。是的,如果需要,您可以将其定义为还接收(指针或引用)该类的另一个实例,但this
无论如何它总是接收。朋友(函数或类)没有得到这个——friend
声明只是意味着其他类私有的名称friend
对. 要访问该类的实际实例,您通常需要将其作为参数传递,或者按该顺序传递。
最后,我要指出的是,前一种忽略了私有继承或受保护继承的可能性。私有继承通常意味着派生类是根据基类实现的。如果(例如)派生类与基类相似,但在设计中不相关,这可能会很方便 - 即,您没有断言派生类的实例可以在任何地方使用需要基类。它对基类的使用是一个实现细节,世界其他地方不需要知道或关心。
受保护的继承几乎是一个错误。它是允许的,因为它与public
,private
和protected
成员(这确实有意义)一致,但对于继承, protected 似乎并没有完成任何有用的事情。