1

これは、私が達成しようとしているものの大まかなイメージです (コンパイルされないため、疑似コードと考えてください)。この例は公開鍵暗号スキームに基づいていますが、問題は設計パターン、テンプレート、および継承に関するものであることに注意してください。

class CryptoProvider
{
public:
    template <typename T>
    virtual T Encrypt ()
    {
        T data;

        return data;
    }
};

class Paillier : public CryptoProvider
{
public:
    typedef int Ciphertext;

    Ciphertext Encrypt ()
    {
        Ciphertext data;
        return data;
    }
};

class ElGamal : public CryptoProvider
{
public:
    struct Ciphertext
    {
    public:
        int c1;
        int c2;
    };

    Ciphertext Encrypt ()
    {
        Ciphertext data;
        return data;
    }
};

基本的に、CryptoProvider でいくつかの一般的な機能を提供したいと考えています。これは、必要に応じて派生クラスによってオーバーライドできます。そうしないと、多くの重複したコードになってしまうからです。変数を作成して別の関数を呼び出すだけの場合Encryptは、すべての派生クラスにこのコードを記述したくありませんが、派生クラスがデータに対して追加の処理を行う必要がある場合は、ベースメソッド。

私が遭遇した最大の制限は、まったく異なる戻り値の型を指定することで Encrypt 関数をオーバーライドできるようにすることです。これを達成する方法について、誰かが私を正しい方向に向けることができますか? 従来の継承に固執する必要がありますか、それともCRTPを使用してコンパイル時/静的ポリモーフィズムを試みる必要がありますか? どこから始めればよいかわかりません。

また、派生クラスに特定のメソッドを実装するように強制したいのですが、最初の問題の解決策で標準の継承を破棄する必要がある場合 (および仮想メソッドの恩恵を受けない場合)、これを達成する方法がわかりません.. .

4

4 に答える 4

2

すべての子クラスには、Ciphertext異なるものとして定義された型があります。これは、 のテンプレート パラメータにすることを提案しますCryptoProvider

template <typename T>
class CryptoProvider
{
public:
    virtual T Encrypt () { ... }
    typedef T Ciphertext;
};

class PaillierBase : public CryptoProvider<int> { ... }

ここでは IMHO CRTP は不要です。

于 2012-07-18T14:45:10.840 に答える
1

これを達成する別の方法を参照してください。ただし、少し回り道があります...これにより、テンプレートと派生可能性に基づく共通の実装の可能性が提供されます。唯一の問題は、CipherText 定義を派生クラス内に配置できないことです。これはあなたにとって大きな問題ではないと思います。これらのクラスをグローバル スコープで定義できれば、追加の派生を回避できます。

template <typename T>
class CryptoProvider
{

public:
    virtual T Encrypt()
    {
        T data;

        return data;
    }
};

class PaillierBase
{
public:
   typedef int Ciphertext;
};

class Paillier : public PaillierBase, public CryptoProvider<PaillierBase::Ciphertext>
{
public:

};

class ElGamalBase
{
public:
    struct Ciphertext
    {
    public:
        int c1;
        int c2;
    };


};

class ElGamal : public ElGamalBase, public CryptoProvider<ElGamalBase::Ciphertext>
{
public:

};

class CustomEncryptorBase
{
public:
    struct Ciphertext
    {
    public:
        char* c1;
        int* c2;
    };


};

class CustomEncryptor : public CustomEncryptorBase, public CryptoProvider<CustomEncryptorBase::Ciphertext>
{
public:

    virtual CustomEncryptorBase::Ciphertext Encrypt()
    {
        CustomEncryptorBase::Ciphertext data;

        //  Do additional processing

        return data;
    }
};

int main()
{
    ElGamal e;
    ElGamalBase::Ciphertext c = e.Encrypt();

    CustomEncryptor ce;
    CustomEncryptorBase::Ciphertext c1 = ce.Encrypt();

    return 0;
 }
于 2012-07-18T15:11:39.447 に答える
1

CRTP は、仮想関数を必要とせずにコンパイル時にオーバーライド可能な機能を提供するように機能します。

template <typename Derived> class CryptoProvider
{
public:
    typename Derived::Ciphertext Encrypt() {
        typename Derived::Ciphertext data;
        return data;
    }
};

class PaillierBase
{
public:
    typedef int Ciphertext;
};

class Paillier : public CryptoProvider<PaillierBase>
{
public:
    void test1() {
        Encrypt();
    }
};

class ElGamalBase
{
public:
    struct Ciphertext {
        int c1;
        int c2;
    };
};

class ElGamal : public CryptoProvider<ElGamalBase>
{
public:
    void test2() {
        Encrypt();
    }
};

戻り値の型は、CRTP テンプレートから派生したときにインスタンス化されるまでに完全な型である必要がある基本クラスで宣言する必要があります。以下のコードは、少なくとも C11 より前のコンパイラでは機能しません。ポイント P では、クラス ElGamal はまだ完全な型ではないため、CryptoProvider::Encrypt() をインスタンス化できません。C11がここで何かを変えるかどうかはわかりません。それは言語のばかげた欠点です、IMHO。

// Doesn't work, unfortunately
class ElGamal : public CryptoProvider<ElGamal> /* P */
{
public:
    struct Ciphertext {
        int c1;
        int c2;
    };
    void test2() {
        Encrypt();
    }
};
于 2012-07-18T14:34:05.990 に答える
0

暗号テキストを保持する CipherText という基本クラスを作成できます。次に、それを返す必要がある特定の型にサブクラス化できます。戻り値の型を基本クラス ポインターとして指定できます。

もちろん、この答えは、何をしようとしているのかによって、正しいか間違っている可能性があります。

于 2012-07-18T14:29:09.860 に答える