从多重继承的模板化基础覆盖 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 本质上是一个被禁止的名字。这就是价格。
随附的代码是我遇到的一些精简示例。
首先,这里有一个更简化的版本可以编译:
#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 本质上是一个被禁止的名字。这就是价格。