3

假设有两个类 A 和 B:

class A {};
class B {};

下面的两个例子在哪些方面有所不同?

示例 1:

class C : public A, public B {}; 

示例 2:

class C
{
    //private
    friend class A;
    friend class B;
}
4

4 回答 4

26

Afriend可以触摸private任何它是朋友的部分(双关语只是稍微有意!;)),但没有任何东西是AB的一部分C- 它只是意味着“A并且B可以触摸C's private bits”)。任何“小于”private的东西当然也可用于Aand B,因此如果Cprotectedorpublic成员,它也将可用。

当您继承时,AandB成为C. 和的任何private部分均不可用于。在“is-a”与“has-a”的命名法中,现在 is-a和 is-a - 换句话说,它是从 继承的,所以它“表现得像从界面的角度来看。ABCCABAA

于 2013-08-06T16:09:36.883 回答
3

有几个很大的不同。继承和友谊是非常不同的。

有了友谊,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
   }
}
于 2013-08-06T16:17:54.403 回答
1

在您使用的上下文中,为了尽我所能回答您的问题,朋友们只需允许您的类共享受保护/私有数据,而继承也会这样做,除了会有更深层次的关系,其中类是相同的(例如与铸造)。

于 2013-08-06T16:10:19.490 回答
1

虽然您得到的答案相当准确,但我认为它们并不完整。特别是,尽管它们解释友谊和继承之间的区别,但并没有真正解释什么时候应该使用哪个,或者区别如何影响您的代码。

继承(在 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,privateprotected成员(这确实有意义)一致,但对于继承, protected 似乎并没有完成任何有用的事情。

于 2015-05-10T18:29:44.633 回答