当前位置:天才代写 > tutorial > C语言/C++ 教程 > C++箴言:毫不重界说担任的非虚拟函数

C++箴言:毫不重界说担任的非虚拟函数

2017-11-06 08:00 星期一 所属: C语言/C++ 教程 浏览:517

副标题#e#

假设我汇报你 class(类)D 从 class(类)B publicly derived(公有担任),并且在 class(类)B 中界说了一个 public member function(公有成员函数)mf。mf 的参数和返回值范例是无关紧急的,所以我们就假设它们都是 void。换句话说,我的意思是:

class B {
 public:
  void mf();
  ...
};
class D: public B { ... };

甚至不必知道关于 B,D,或 mf 的任何工作,给定一个范例为 D 的 object(工具)x,

D x; // x is an object of type D

对此你或者很是受惊,

B *pB = &x; // get pointer to x
pB->mf(); // call mf through pointer

的行为差异于以下代码:

D *pD = &x; // get pointer to x
pD->mf(); // call mf through pointer

因为在两种环境中,你都挪用了 object(工具)x 中的 member function(成员函数)mf。因为两种环境中都是同样的 function(函数)和同样的 object(工具),它们的行为应该有沟通的方法,对吗?

是的,应该。可是也大概不,出格地,假如 mf 是 non-virtual(非虚拟)而 D 界说了它本身的版本的 mf:

class D: public B {
 public:
  void mf(); // hides B::mf; see Item33
  ...
};
pB->mf(); // calls B::mf
pD->mf(); // calls D::mf

这种行为两面性的原因是像 B::mf 和 D::mf 这样的 non-virtual functions(非虚拟函数)是 statically bound(静态绑定)的(拜见 Item 37)。这就意味着因为 pB 被声明为 pointer-to-B 范例,所以,纵然就像本例中的做法,让 pB 指向一个从 B 担任的类的工具,通过 pB 挪用的 non-virtual functions(非虚拟函数)也老是界说在 class B 中的那一个。


#p#副标题#e#

在另一方面,virtual functions(虚拟函数)是 dynamically bound(动态绑定)的(再次拜见 Item 37),所以它们不会产生这个问题。假如 mf 是一个 virtual function(虚拟函数),无论通过 pB 照旧 pD 挪用 mf 都将导致 D::mf 的挪用,因为 pB 和 pD 都实际地指向一个 type(范例)D 的 object(工具)。

假如你在编写 class D 并且你重界说了一个你从 class B 担任到的 non-virtual function(非虚拟函数)mf,D 的 objects(工具)将很大概表示出不协调的行为。出格是,当 mf 被挪用时,任何给定的 D object(工具)的行为既大概像 B 也大概像 D,并且抉择因素与 object(工具)自己无关,可是和指向它的 pointer(指针)的声明范例有关。references(引用)也会像 pointers(指针)一样表示出莫名其妙的行为。

但这仅仅是一个从实用出发的论据。我知道,你真正需要的是不能重界说 inherited non-virtual functions(通过担任获得的非虚拟函数)的理论上的来由。我很愿意效劳。

前文表明白 public inheritance(公有担任)意味着 is-a,在《C++箴言:接口担任和实现担任》一文中记述了为什么在一个 class(类)中声明一个 non-virtual function(非虚拟函数)是为这个 class(类)设定一个 invariant over specialization(逾越非凡化的稳定量),假如你将这些履历应用于 classes(类)B 和 D 以及 non-virtual member function(非虚拟函数)B::mf,那么:

每一件合用于 B objects(工具)的工作也合用于 D objects(工具),因为每一个 D objects 都 is-a(是一个)D objects(工具);

从 B 担任的 classes(类)必需同时担任 mf 的 interface(接口)和 implementation(实现),因为 mf 在 B 中是 non-virtual(非虚拟)的。

#p#副标题#e#

此刻,假如 D 重界说 mf,你的设计中就有了一处抵牾。假如 D 真的需要实现差异于 B 的 mf,并且假如每一个 B objects(工具)——无论如何非凡——都必需利用 B 对 mf 的实现,那么每一个 D 都 is-a(是一个)B 就完全不创立。在那种环境下,D 就不该该从 B publicly inherit(公有担任)。另一方面,假如 D 真的必需从 B publicly inherit(公有担任),并且假如 D 真的需要实现差异于 B 的 mf,那么 mf 反应了一个 B 的 invariant over specialization(逾越非凡化的稳定量)就不会创立。在那种环境下,mf 应该是 virtual(虚拟)的。最后,假如每一个 D 真的都 is-a(是一个)B,并且假如 mf 真的相当于一个 B 的 invariant over specialization(逾越非凡化的稳定量),那么 D 就不会真的需要重界说 mf,并且想都不能想。

不管利用那一条法则,必需做出某些让步,并且无条件地克制重界说一个 inherited non-virtual function(通过担任获得的非虚拟函数)。

假如阅读本文给你 déjà vu(似曾领会)的感受,那大概是因为你已经阅读了《C++箴言:多态基类中将析构函数声明为虚拟》,该文表明白为什么 polymorphic base classes(多态基类)中的 destructors(析构函数)应该是 virtual(虚拟)的。假如你违反了谁人 guideline(指导目的)(譬喻,假如你在一个 polymorphic base class(多态基类)中声明一个 non-virtual destructor(非虚拟析构函数)),你也同时违反了这里这个 guideline(指导目的),因为 derived classes(派生类)老是要重界说一个 inherited non-virtual function(通过担任获得的非虚拟函数):base class(基类)的 destructor(析构函数)。甚至对付没有声明 destructor(析构函数)的 derived classes(派生类)这也是创立的,因为,就像《C++箴言:相识C++偷偷加上和挪用了什么》中的表明,destructor(析构函数)是一个“假如你没有界说你本身的,编译器就会为你生成一个”的 member functions(成员函数)。其实,《C++箴言:多态基类中将析构函数声明为虚拟》只相当于本文的一个非凡环境,尽量它重要到足以把它提出来独立成篇。

Things to Remember

·毫不要重界说一个 inherited non-virtual function(通过担任获得的非虚拟函数)。

 

    关键字:

天才代写-代写联系方式