5

我围绕 GSL 的某些部分编写了一个小的 C++ 包装器,并遇到了以下难题(对我而言)。代码(简化为基本内容)如下:

    #include <stdlib.h>
    struct gsl_vector_view {};

    class Vector : protected gsl_vector_view {
            public:
            Vector ( const Vector& original );
            Vector ( const gsl_vector_view view );
    };

    class AutoVector : public Vector {
            public:
            explicit AutoVector ( const size_t dims );
    };

    void useVector ( const Vector b ) {}

    void test () {
            const AutoVector ov( 2 );
            useVector( ov );
    }

不会使用 gcc 4.4.5 g++ -c v.cpp 编译但会产生

     In function ‘void test()’:
    19: error: call of overloaded ‘Vector(const AutoVector&)’ is ambiguous
    7: note: candidates are: Vector::Vector(gsl_vector_view)
    6: note:                 Vector::Vector(const Vector&)
    19: error:   initializing argument 1 of ‘void useVector(Vector)’

我很惊讶,受保护的基类 gsl_vector_view 被调用 useVector( Vector ) 考虑在内。我会认为 useVector 属于“C++ 编程语言”的说法中的“公众”,第 3 e.,p。405,因此无法访问该受保护的信息,因此不会被它混淆。我知道我可以通过将构造函数声明为来消除歧义

    explicit Vector ( const gsl_vector_view view );

我不知道(老实说,也不明白),当我将构造函数声明为时,重​​载调用的歧义消失了

    Vector ( const gsl_vector_view& view );

即通过引用传递参数(无论如何我都会考虑正确的做事方式)。

4

2 回答 2

4

重载解决方案是在访问检查之前完成的,这就是为什么即使是受保护的基类的成员也被考虑在内的原因。

过载解决方案在标准的第 13.3 章中进行了描述。我的解释是绑定const AutoVector ovVector ( const Vector& original );用户定义的转换,一种派生到基础的转换([13.3.3.1.4/1]) 类型。对于Vector ( const gsl_vector_view view );,转换顺序也是用户定义的转换,因为它是左值到右值的转换,然后是用户定义的转换。因此,两个转换序列被认为是相等的,没有一个比另一个更好,因此您会产生歧义。

现在,如果将 ctor 更改为Vector ( const gsl_vector_view& view );,则两种转换都是左值到值的转换,然后是用户定义的转换(派生到基础转换)。这两个可以排序([13.3.3.2/4])并且转换为const Vector&被认为更好,因此没有歧义。

于 2011-08-23T08:30:35.070 回答
1

protected这个问题与继承或构造函数本身无关。这个问题也会在正常的函数调用中持续存在(无论继承如何)。

当您在所有重载版本中通过引用传递时,将选择最近的基类(如果有超过 1 个最接近的基类,则它的格式不正确)。

在按值传递的情况下,所有函数都被认为是同样好的候选者。因此,您会收到此编译错误。有一小段来自标准的引用,与您的问题有些相符。

§ 13.3.1 (5)
... 对于没有 ref-qualifier 声明的非静态成员函数,适用附加规则: - 即使隐式对象参数不是 const-qualified,右值也可以绑定到参数只要在所有其他方面,参数都可以转换为隐式对象参数的类型。

于 2011-08-23T09:32:40.080 回答