调用装饰的基类时的模糊访问 [英] ambiguous access when calling a decorated base class

查看:200
本文介绍了调用装饰的基类时的模糊访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个类,可以用一组附加模板来装饰,以提供额外的功能。每个附加组件需要能够调用基类,并且用户需要能够调用基类(直接或使用CMyClass作为代理)。
不幸的是,编译器不能告诉我正在调用哪个基类,我得到不明确的访问错误。

I have a class that can be decorated with a set of add-on templates to provide additional functionality. Each add-on needs to be able to call the base class and the user needs to be able to call the base class (either directly or using the CMyClass as a proxy). Unfortunately, the compiler can't tell which base class I'm calling and I get ambiguous access errors.

template< class T >
class AddOn_A : public T
{
public: 
    AddOn_A( int x ) : T( x ) 
    {};

    int AddOne()
    {
        T* pT = static_cast< T* >( this );
        return pT->GetValue() + 1;
    };
};

template< class T >
class AddOn_B : public T
{
public: 
    AddOn_B( int x ) : T( x ) 
    {};

    int AddTwo()
    {
        T* pT = static_cast< T* >( this );
        return pT->GetValue() + 2;
    };
};

class CBase
{
public:
    explicit CBase( int x ) : x_( x ) 
    {
    };

    int GetValue()
    {
        return x_;
    };

private:
    int x_;
};

// define an empty AddOn
template< class > struct empty {};

// forward declaration and Add-On defaults
template< template< class > class AddOn1 = empty,
          template< class > class AddOn2 = empty,
          template< class > class AddOn3 = empty >
class CMyClass;

// specialized template for the default case
template<> class CMyClass< empty, empty, empty > : public CBase
{
public:
    CMyClass( int x ) : CBase( x ) 
    {};
};

// actual definition
template< template< class > class AddOn1,
          template< class > class AddOn2,
          template< class > class AddOn3 >
class CMyClass : public AddOn1< CBase >,
                 public CMyClass< AddOn2, AddOn3 >
{
public:
    CMyClass( int x ) : AddOn1< CBase >( x ),
                        CMyClass< AddOn2, AddOn3 >( x )
    {};
};

int _tmain( int argc, _TCHAR* argv[] )
{
    CMyClass< AddOn_A > A( 100 );

    // error C2385: ambiguous access of 'GetValue'
    //     1>        could be the 'GetValue' in base 'CBase'
    //     1>        or could be the 'GetValue' in base 'CBase'
    _ASSERT( A.GetValue() == 100 );

    // error C2385: ambiguous access of 'GetValue'
    //     1>        could be the 'GetValue' in base 'CBase'
    //     1>        or could be the 'GetValue' in base 'CBase'
    _ASSERT( A.AddOne() == A.GetValue() + 1 );

    // works
    _ASSERT( A.AddOne() == 101 );

    CMyClass< AddOn_A, AddOn_B > AB( 100 );

    // same errors as above
    _ASSERT( AB.GetValue() == 100 );

    // same errors as above
    _ASSERT( AB.AddTwo() == AB.GetValue() + 2 );

    // works
    _ASSERT( AB.AddTwo() == 102 );

    return 0;
}

任何人都可以指出我可能做错了什么?

Can anybody point out what I may be doing wrong?

谢谢,
PaulH

Thanks, PaulH

推荐答案

方法,我也可以:)

编辑:让我们添加AddOnValues来解决 this 以及

let's add the AddOnValues to solve this as well

这里的问题是多继承。跟踪这样的图是不容易的,但如果仔细看你会看到 CMyClass< AddOn_A> 从CBase继承两次。

The problem here is the Multi-Inheritance. Tracing such a diagram is not easy but if you look closely you'll see that CMyClass<AddOn_A> inherits twice from CBase.


  1. CMyClass< AddOn_A> < - AddOn_A< CBase> ; - CBase

  2. CMyClass< AddOn_A> code> CMyclass <空,空,空> < - CBase

  1. CMyClass<AddOn_A> <-- AddOn_A<CBase> <-- CBase
  2. CMyClass<AddOn_A> <-- CMyclass<empty,empty,empty> <-- CBase

问题是,您使用策略方法,而不是装饰器方法。在正确的装饰器方法中,层次结构是严格线性的,并且一次只有一个模板参数。让我们得到基础:

The problem is that you used a policy approach, instead of a Decorator approach. In a proper Decorator approach, the hierarchy is strictly linear and you only have one template parameter at a time. Let's get the basis:

// Note that the static_cast are completely unnecessary
// If you inherit from T then you can freely enjoy
// its public and protected methods
template< class T >
class AddOn_A : public T
{
public:
    enum { AddOnValues = T::AddOnValues | 0x01 }; // this hides T::AddOnValues

    AddOn_A( int x ) : T( x ) {};

    int AddOne()
    {
        return this->GetValue() + 1;
    };
};

template< class T >
class AddOn_B : public T
{
public:
    enum { AddOnValues = T::AddOnValues | 0x02 }; // this hides T::AddOnValues

    AddOn_B( int x ) : T( x ) {};

    int AddTwo()
    {
        return this->GetValue() + 2;
    };
};

class CBase
{
public:
    enum { AddOnValues = 0x00 };

    explicit CBase( int x ) : x_( x ) {}
    virtual ~CBase() {} // virtual destructor for inheritance

    int GetValue() const { return x_; }; // const method

private:
    int x_;
};

现在我们可以得到实际使用!

Now we can get to the actual use!

// First, the typedef approach
typedef AddOn_B< AddOn_A< CBase > > CMyClass;
CMyClass myObject(3);
std::cout << myObject.GetValue() << std::endl;
std::cout << myObject.AddOne() << std::endl;
std::cout << myObject.AddTwo() << std::endl;

很简单不是吗?明显的缺点是你不添加功能...

Quite easy isn't it ? The obvious drawback is that you don't add functionality there...

 // I want more!
 template < class T >
 class CMyClassImpl: public T
 {
   // Whatever you want
 };

 CMyClassImpl< AddOn_B< AddOn_A< CBase > > > myObject(3);

好吧...不那么美丽我猜...更好?

Okay... not so beautiful I guess... Even better ? Well, we can just use a wrapper!

 // Even better
 template <>
 class CMyClass: public CMyClassImpl < CBase > {};

 template < template <class> class AddOn1>
 class CMyClass: public CMyClassImpl <AddOn1 < CBase > > {};

 template < template <class> class AddOn1,
            template <class> class AddOn2 >
 class CMyClass: public CMyClassImpl < AddOn2 < AddOn1< CBase > > > {};

 template < template <class> class AddOn1,
            template <class> class AddOn2,
            template <class> class AddOn3 >
 class CMyClass: public CMyClassImpl < AddOn3 < AddOn2< AddOn1< CBase > > > > {};

 // Go on with as much specializations as you wish

 CMyClass < AddOn_A, AddOn_B > myObject(3);

当然,最后一个解决方案会在调用站点保存输入,但是你必须真正工作在你的类上:)

Of course, the last solution saves typing at the calling site, but you've got to really work on your class :)

此外,你必须在继承的每一步重复各种构造函数,我迅速证明...无聊。

Also, you have to repeat the various constructors at each step of the inheritance, which my rapidly prove... boring.

有预处理器宏,但...最后一次我花了500行来生成一些简单的东西,所以不要打扰和键入,真的:)

There are preprocessor macros out there, but... last time it took me some 500 lines to generate something quite simple, so don't bother and type, really :)

这篇关于调用装饰的基类时的模糊访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆