友谊和继承有什么区别?
What's the difference between friendship and inheritance?
假设有两个类A和B:
class A {};
class B {};
以下两个示例在哪些方面有所不同?
示例 1:
class C : public A, public B {};
示例 2:
class C
{
//private
friend class A;
friend class B;
}
friend
可以触摸它的朋友的private
部分(双关语只是稍微有意!;)(,但A
和B
都不是C
的一部分 - 它只是意味着"A
和B
可以触摸C
的私人位"(。任何"小于"private
的东西当然也可供A
和B
使用,因此,如果C
有protected
或public
成员,那也将可用。
当您继承时,A
和B
成为C
的一部分。A
和B
的任何private
部分都不适用于C
。在"is-a"与"has-a"命名法中,C
现在是A
和is 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++ 中(的主要用途是在基类中定义接口,并在多个派生类中的每一个中实现该接口。派生类必须实现的接口部分通常由基类中的纯虚函数表示。
friend
在 C++ 中发布的主要用途是定义构成接口一部分的内容,但由于语法原因不能成为成员函数。一个非常常见的例子是流插入或提取运算符。若要将这些函数实现为成员函数,它们必须是流类的成员。由于我们不想不断修改流类,因此它们是自由函数,它们将对流的引用作为其左参数,并将对它们插入/提取的类型(可能是 const(对象的引用作为其右操作数。
这些不一定是类的friend
- 它们可以编写为仅使用类的公共接口。但是,如果这样做,这通常意味着该类在其公共接口中公开的内容比其他必要内容要多。界面不再最小,这往往表明设计有问题。
但需要注意的是:您可以在类定义中定义一个友元函数:
class Foo {
// ...
friend std::ostream &operator<<(std::ostream &os, Foo const &f) {
// ...
}
};
乍一看,这可能看起来很奇怪(语法上确实如此(。即使它是在类定义中定义的,friend
也意味着这不是成员函数。至少在我看来,这相当准确地反映了它的情况:从概念上讲,它是类的一部分。它可以访问私有成员,就像类的任何其他成员一样。它是一个自由函数而不是成员函数这一事实纯粹是一个实现工件,本质上与代码的设计无关。
这也指出了friend
交付和继承之间的另一个区别:使用继承时,通常主要处理成员函数。每个成员函数仍接收一个this
指针,因此每个成员函数都直接与类的特定实例相关联。是的,如果需要,您可以将其定义为也接收(指针或引用(类的另一个实例,但无论如何,它始终接收this
。朋友(函数或类(不明白这一点 - friend
声明只是意味着该其他类私有的名称对friend
可见。要访问该类的实际实例,通常需要将其作为参数或该顺序传递。
最后,我要指出,前面的那种忽略了私有或受保护继承的可能性。私有继承通常意味着派生类是按照基类实现的。如果(例如(派生类与基类相似,但在设计中不相关,则这可能很方便 - 即,您没有断言派生类的实例可以在需要基类实例的任何地方使用。它对基类的使用是世界其他地方不需要知道或关心的实现细节。
受保护的继承几乎是一个错误。这是允许的,因为它与public
、private
和protected
成员一致(这确实有意义(,但对于继承,受保护似乎根本没有完成任何有用的事情。
- 向量 <int> a {N, 0} 和 int arr a[N] = {0} 的时间复杂度有什么区别
- 在 .h 文件中的类中声明静态变量和在.cpp文件中声明"global"变量有什么区别
- 我是C++编程的新手,这些代码之间有什么区别,我应该使用哪一个
- 返回常量对象引用 (getter) 和仅返回字符串有什么区别?
- Qt:remove() 和 rmdir() 有什么区别
- 这 4 个 lambda 表达式之间有什么区别?
- 将向量作为类>(值)<向量启动和向量<类>[值]有什么区别
- typedef 枚举和枚举类有什么区别?
- &C::c 和 &(C::c) 有什么区别?
- ascii 和 unicode 在处理级别有什么区别吗?
- C 中的常量限定符和 C++ 中的常量限定符有什么区别?
- "ABC" 和 "ABC" ) 在C++中有什么区别?
- 空指针常量 (nullptr)、空指针值和空成员指针值之间有什么区别?
- 引用捕获和在 lambda 中通过引用发送参数有什么区别 (C++)
- 两种访问I2C总线的方法有什么区别?
- 两种模板示例有什么区别?
- 这两种C++语法之间有什么区别?
- lua 5.0.2 模块和 5.3.5 有什么区别?
- C++中"typedef"、"using"、"namespace"和"using namespace"有什么区别?
- std::vector和llvm::SmallVector之间有什么区别?什么时候用哪一个