分享

Why make your classes final? | Andrzej's C++ blog

 astrotycoon 2017-05-25

In this short post I wanted to share a small but interesting thing I learnt. You probably know that in C++11 it is possible to require that no?ne must inherit from your class. You just declare your class as “final”:

struct B final {
  int i;
};

struct D : B {   // ERROR
  int j;
};

This feature is already implemented in new compilers. I know at least of three: Clang 3.0, GCC 4.7 and VC 11. I was often wondering why anyone would want to prohibit inheritance from one’s class; in C++. Recently I came across one good example where this is useful.

Perhaps there are some good reasons to do that, which I always failed to understand or notice. I would be glad to learn about them. The one I found comes from the recent ISO C++ Committee’s mailing. The mailing is in general an interesting resource to learn about the development and the future of C++. You can find the pre-Portland mailing here. The proposal in question is N3407 (Proposal to Add Decimal Floating Point Support to C++). The author proposes the addition of three types that would represent decimal floating-point types: decimal32, decimal64 and decimal128. Implementations (i.e., compiler writers) would have the freedom to implement them as either built-in or user-defined types. This freedom has certain impact on programmers. Suppose you happen to work with the implementation that provides decimal64 as user-defined type. Suppose you decide to inherit from it in order to provide some additional features. So far, so good. But now, suppose you need to migrate your program or library to other platforms (and compilers), and one of them implements decimal64 as built-in type. Now your program no longer compiles and it may take long time to rewrite it.

In contrast, if type decimal64 (on platforms where it is a user-defined type) is declared as final, you are warned by the compiler even on your initial platform that you must not inherit from it: in order that your program/library be platform-independent; or compiler version-independent. So, in general, you can prevent inheritance because you allow the possibility of changing your implementation to a built-in type, and want to spare your users unpleasant surprises in the future. This same technique could be applied when implementing type std::vector<T>::iterator, which on some platforms/configurations could be implemented as T*.

Advertisements

Rate this:

 
6 Votes

Share this:

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多