多重定義
テンプレートと多重定義

C++の様に多重定義とテンプレートを使用可能な言語では、両方の機能を組み合わせることにより静的な多態を実現することができる。また、PostgreSQLのストアドプロシージャーの様なテンプレートを備えていない言語でも同様の多態を実現できる場合がある。
以下に例を示す。
#include <cmath>
#include <cstdlib>

// 引数valueの符号に応じて、-1, 1または0を返す関数。
// ※absを使用しているため、引数に指定できる値の値の範囲はこの関数の引数と同じ型(反変な型)をとるabsの仕様に依存する。
template<class Type> Type Sign( Type const &value )
{
    return Type() == value ? Type() : abs( value ) / value; // 除算演算子及び、abs関数の実体はSignの引数によって変わる
}

int main(void)
{
    double value = -2;
    std::valarray<double> array( 2 );

    double value_sign = Sign( value ); // double型の-1, 1または0が返る
    std::valarray<double> array_sign = Sign( array ); // -1, 1または0を含むvalarrayの値が返る

    return EXIT_SUCCESS;
}
この例ではSign関数内部の演算子とabs関数がSign関数の引数に指定した値によって変化する。なお上記関数テンプレートは複素数型 std::complex に対して適用することもできる。その場合、結果は正規化された複素数（正規化ベクトル）となり、符号関数の複素数への拡張に一致する。
この様にテンプレートと多重定義を備える言語では、多重定義でオーバーライドを代用することができる。
多重定義による多態は、コンパイル時にしか実現できないという問題があるものの単純なオーバーライドでは実現しづらい各種柔軟性を備えている。
まず、メンバー関数だけでなく大域スコープの関数をクラスのインターフェースの一部として見做す事が出来るようになる。これにより、単に手続き型の要素でしか無かった大域スコープの関数をオブジェクト指向機能の一要素として組み入れる事が出来る。そして、大域スコープの関数がインターフェースとして機能し始める事によりクラスだけでなく、intやdouble型といったメンバー関数を持てない型にもオブジェクト指向の恩恵が得られる様になるのである。
次に、大域スコープの関数は直接クラスに所属しないという特性によりメンバー関数より柔軟な拡張性を得る事が出来る。例えば、外部のライブラリーのあるクラスにメンバー関数を追加することは、外部のライブラリーに手を加えなければいけないため事実上無理である。それに対し大域スコープの関数を追加する場合は、外部のライブラリーに手を加える必要がなく容易である。また、関数をテンプレートで実装すれば複数のクラスを横断的に拡張できる。先にテンプレート関数が存在する場合や、拡張対象のクラスの親クラスに対する関数が存在する場合、新たに、より具体的な型を引数に取る関数を追加することで静的なオーバーライドが可能となる。
次に、単一ディスパッチでは不可能な多重ディスパッチを模倣できるという点がある。これにより、例えば矩形を描画しようとする際、描画先デバイスが矩形の描画に対応していれば、デバイスに直接矩形情報を送り、描画先デバイスが矩形描画に対応していなければ、パスや線分等その他の機能を使って矩形を描画するといった処理が自然な形で記述可能となる。
なお大域スコープと記述しているが名前空間の中にあっても次の例のように多態性の実現は可能である。この仕組みを実引数依存の名前探索という。
#include <cstdlib>

namespace Graphics
{
        class Line { /* 省略 */ };
        class Ellipse { /* 省略 */ };

        class Square
        {
                /* 省略 */
                Line At( size_t index ) const; // 四角形の辺を返す関数
                /* 省略 */
        };

        void Draw( ... )
        {
        }

        // 四角形を描画する
        template<class Type> void Draw( Type &device, Square const &shape )
        {
                Draw( device, shape.At( 0 ) );
                Draw( device, shape.At( 1 ) );
                Draw( device, shape.At( 2 ) );
                Draw( device, shape.At( 3 ) );
        }
}

namespace RasterDevice
{
        struct Device { /* 省略 */ };
        // Raster形式用に線分を描画する
        void Draw( Device &device, Graphics::Line const &shape );
}

namespace VectorDevice
{
        struct Device { /* 省略 */ };
        // Vector形式用に線分を描画する
        void Draw( Device &device, Graphics::Line const &shape );
}

namespace DisplayDevice
{
        struct Device { /* 省略 */ };
        // 表示装置用に線分を描画する
        void Draw( Device &device, Graphics::Line const &shape );
}

int main()
{
        RasterDevice::Device device0;
        VectorDevice::Device device1;
        DisplayDevice::Device device2;

        Draw( device0, Graphics::Square( 0, 0, 1, 1 ) ); // 内部でRasterDevice::Draw( Device &, Graphics::Line const & )を呼び出す
        Draw( device1, Graphics::Square( 0, 0, 1, 1 ) ); // 内部でVectorDevice::Draw( Device &, Graphics::Line const & )を呼び出す
        Draw( device1, Graphics::Square( 0, 0, 1, 1 ) ); // 内部でDisplayDevice::Draw( Device &, Graphics::Line const & )を呼び出す

        Draw( device0, Graphics::Ellipse( 0, 0, 1, 1 ) ); // Graphics::Draw( ... )を呼び出す
        Draw( device1, Graphics::Ellipse( 0, 0, 1, 1 ) ); // Graphics::Draw( ... )を呼び出す
        Draw( device2, Graphics::Ellipse( 0, 0, 1, 1 ) ); // Graphics::Draw( ... )を呼び出す

        return EXIT_SUCCESS;
}