C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] نسخه متنی

اینجــــا یک کتابخانه دیجیتالی است

با بیش از 100000 منبع الکترونیکی رایگان به زبان فارسی ، عربی و انگلیسی

C++.Coding.Standards.1918.Rules.Guidelines [Electronic resources] - نسخه متنی

Herb Sutter, Andrei Alexandrescu

| نمايش فراداده ، افزودن یک نقد و بررسی
افزودن به کتابخانه شخصی
ارسال به دوستان
جستجو در متن کتاب
بیشتر
تنظیمات قلم

فونت

اندازه قلم

+ - پیش فرض

حالت نمایش

روز نیمروز شب
جستجو در لغت نامه
بیشتر
لیست موضوعات
توضیحات
افزودن یادداشت جدید


Discussion


Dynamic polymorphism comes in the form of classes with virtual functions and instances manipulated indirectly (through pointers or references). Static polymorphism involves template classes and template functions.

Polymorphism means that a given value can have more than one type, and a given function can accept arguments of types other than the exact types of its parameters. "Polymorphism is a way of gaining some of the freedom of dynamic type checking without giving up the benefits of static type checking." [Webber03]

The strength of polymorphism is that the same piece of code can operate on different types, even types that were not known at the time the code was written. Such "post-hoc applicability" is the cornerstone of polymorphism because it amplifies the usefulness and reusability of code (see Item 37). (Contrast that with monomorphic code that rigidly operates only on the concrete types it was meant to work with.)

Dynamic polymorphism via public inheritance lets a value have more than one type. For example, a

Derived* p can be viewed as a pointer not only to a

Derived , but to an object of any type

Base that's a direct or indirect base of

Derived (the

subsumption property). Dynamic polymorphism is also referred to as

inclusion polymorphism because the set modeled by

Base includes the specializations modeled by

Derived .

Due to its characteristics, dynamic polymorphism in C++ is best at:

  • Uniform manipulation based on superset/subset relationships:
    Different classes that hold a superset/subset (base/derived) relationship can be treated uniformly. A function that works on

    Employee objects works also on

    Secretary objects.

  • Static type checking:
    All types are checked statically in C++.

  • Dynamic binding and separate compilation:
    Code that uses classes in a hierarchy can be compiled apart from the code of the entire hierarchy. This is possible because of the indirection that pointers provide (both to objects and to functions).

  • Binary interfacing:
    Modules can be linked either statically or dynamically, as long as the linked modules lay out the virtual tables the same way.


Static polymorphism via templates also lets a value have more than one type. Inside a

template<class T> void f( T t ) {

/*…*/

}, t can have any type that can be substituted inside

f to render compilable code. This is called an "implicit interface," in contrast to a base class's explicit interface. It achieves the same goal of polymorphismwriting code that operates on multiple typesbut in a very different way.

Static polymorphism is best at:

  • Uniform manipulation based on syntactic and semantic interface:
    Types that obey a syntactic and semantic interface can be treated uniformly. Interfaces are syntactic and implicit (not signature-based and explicit), and so allow any type substitution that fits a given syntax. For example, given the statement

    int i = p->f( 5 ) : If

    p is a pointer to a

    Base class type, this calls a specific interface function, such as perhaps a

    virtual int f(int) . But if

    p is of a generic type, this call can bind to a myriad of things, including that it might invoke an overloaded

    operator-> that returns a type defining the function

    X f(double) where

    X is convertible to

    int .

  • Static type checking:
    All types are checked statically.

  • Static binding (prevents separate compilation):
    All types are bound statically.

  • Efficiency:
    Compile-time evaluation and static binding allow optimizations and efficiencies not available with dynamic binding.


Decide on your priorities, and use each type of polymorphism for its strengths.

Prefer to blend both kinds of polymorphism to combine their benefits while trying not to combine their drawbacks:

  • Static helps dynamic:
    Use static polymorphism to implement dynamically polymorphic interfaces. For example, you might have an abstract base class

    Command and define various implementations as

    template<

    /*…*/

    > class ConcreteCommand : public Command . Examples include implementing the Command and Visitor design patterns (see [Alexandrescu01] and [Sutter04]).

  • Dynamic helps static:
    Offer a generic, comfortable, statically bound interface, but internally dispatch dynamically, so you offer a uniform object layout. Good examples are discriminated union implementations (see [Alexandrescu02b] and [Boost]) and

    tr1::shared_ptr 's

    Deleter parameter (see [C++TR104]).

  • Any other blend:
    A bad blend that combines the weaknesses of both is worse than either alone; a good blend that combines the benefits of both is better than either alone. For example, don't put virtual functions into a class template unless you want

    all virtual functions to be instantiated every time (this is in sharp contrast to nonvirtual functions of templated types). The code size hit can be astronomical, and you may overconstrain your generic type by instantiating functionality that is never needed. The standard facets made this mistake. Don't make it again.



/ 521