使用抽象返回类型设计继承



这是我试图实现的目标的大致图像(它不会编译,所以考虑它的伪代码)。请注意,尽管该示例是基于公钥密码方案的,但问题在于设计模式、模板和继承。

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进行编译时/静态多态性?我不知道从哪里开始。

我也想强制派生类来实现某些方法,但我不确定如何实现这一点,如果第一个问题的解决方案要求我放弃标准继承(我不会从虚拟方法中受益)。。。

您的所有子类都定义了Ciphertext类型,将其定义为不同的类型。这建议将其作为CryptoProvider的模板参数。

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

IMHO CRTP在这里是不必要的。

查看实现此目标的另一种方法。虽然有点圆。。。这提供了基于模板和可派生性的通用实现的可能性。唯一的问题是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;
 }

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();
    }
};

您可以创建一个名为CipherText的基类,在其中保存密文。然后,您可以将其子类化为需要返回的特定类型。您可以将返回类型指定为基类指针。

当然,这个答案可能是对的,也可能是错的,这取决于你要做的事情

最新更新