从多重继承的模板化基础覆盖 C++ 方法 class

Override C++ method from multiply inherited templated base class

随附的代码是我遇到的一些精简示例。

首先,这里有一个更简化的版本可以编译:

#include <string>

template<typename T>
class Base
{
public:
    Base() {}
    virtual ~Base() {}

    virtual size_t Size (void) const = 0;
};

template<typename T>
class Derived : public virtual Base<T>
{
public:
    Derived() {}
    virtual ~Derived() {}

    virtual size_t Size (void) const override { return 0; }
};

class Impl : public virtual Derived<std::string>,
    public virtual Base<char const *>
{
public:
    Impl() {}
    virtual ~Impl() {}

    using Base<char const *>::Size;
    virtual size_t Size() const override { return 1; }
};

int
main(int argc, char **argv)
{
    Impl oImpl;
}

问题是能够实施 Base<std::string>::Size() 以及 Base<char const *>::Size() 在达到这个阶段方面发挥了重要作用。 (using 语句是关键。)

但是,问题在于,在实际代码中,我不仅返回 size_t,而且返回嵌套 class.

的实例
#include <string>

template<typename T>
class Base
{
public:
    Base() {}
    virtual ~Base() {}

    class Contained
    {
    public:
        Contained();
        virtual ~Contained();
    };
    virtual Contained begin (void) const = 0;
};

template<typename T>
class Derived : public virtual Base<T>
{
public:
    Derived() {}
    virtual ~Derived() {}

    virtual typename Base<T>::Contained begin (void) const override
        { return typename Base<T>::Contained(); }
};

class Impl : public virtual Derived<std::string>,
    public virtual Base<char const *>
{
public:
    Impl() {}
    virtual ~Impl() {}

    using Base<char const *>::begin;
    virtual typename Base<char const *>::Contained begin() const override
        { return typename Base<char const *>::Contained(); }
    /* virtual typename Base<char const *>::Contained Base<char const *>::begin() const override
        { return typename Base<char const *>::Contained(); } */
};

int
main(int argc, char **argv)
{
    Impl oImpl;
}

不知何故,g++/clang++ 认为这是 Base<std::string>::Size 的重新定义,而不是 Base<char const *>::Size——它抱怨无效的协变类型。因此,在第一个代码示例中运行良好的 using 语句在这里无效。

如果我尝试完全限定名称,即注释掉的部分,g++ 给我 cannot define member function 'Base<const char*>::Size' within 'Impl' (没有说明原因),而 clang++ 给我 non-friend class member 'Size' cannot have a qualified name (我没有完全理解)。

有谁知道如何覆盖来自同一模板化基础的不同实例的方法class?

如果有人感兴趣,Base 是一个通用的“可枚举”class,我正在尝试创建一个 class,它具有可变接口(即派生自 Base<std::string>) 和一个只读接口(即派生自 Base<char const *>),不会泄漏字符串数据的内部存储方式。 (一般来说,我试图在 C++ 中实现 C# 风格的可枚举接口,例如,这样客户端就不必知道底层 class 是基于列表、向量、集合、映射或其他任何东西,只有它包含的值可以通过非特定接口枚举 class...暗示 Contained 实际上是一个迭代器 class).

你所拥有的本质上是这样的:

struct A { 
    virtual int foo() { return 0;} 
};

struct B { 
    virtual double foo() { return 0;} 
};

struct C : A, B {
    int foo() override { return 42; }
    double foo() override { return 3.14; }
};

糟糕!你不能那样做。 C 中 foo() 的每个覆盖器覆盖所有基 类 中的所有 foo()(相同的参数列表,任何 return 类型)。摆弄 using 不会改变这一点。

您基本上需要重命名 foo,以便 C 继承两个不同名称的函数。 Stroustrup 提出了一种完全可以做到这一点的技术(我认为在 D&E 中,但不要引用我的话)。

struct A { 
    virtual int foo() { return 0;} 
};
 
struct B { 
    virtual double foo() { return 0;} 
};
 
struct AA : A {
   virtual int foo1() { return 1; }
   // Essentially rename foo to foo1
   int foo() override { return foo1(); }
};
 
struct BB : B {
   virtual double foo2() { return 1; }
   // Essentially rename foo to foo2
   double foo() override { return foo2(); }
};
 
struct C : AA, BB {
    int foo1() override { return 42; }
    double foo2() override { return 3.14; }
};

现在 C 仍然有两个名为 foo() 的函数,但它们被冻结了。从现在开始,您只能操作 foo1 和 foo2。当然你仍然可以通过 A 和 B 调用 foo(),它们将调用正确的版本。

所以是的,C::foo 本质上是一个被禁止的名字。这就是价格。