Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

visibility issue for copy constructor of base class

I have a class (let's call it base for the moment) that has a protected interface, including protected constructors etc. Some functions of base return an instance of base by value:

class base {
protected:
    base() {}
    base (base const &other) {}  // line 6
    base foo () {
        base ret;
        return ret;
    }
};

These functions are wrapped in the derived classes to return the derived type like so:

class derived : public base {
private:
    derived(base const &b) : base(b) {}
public:
    derived() : base() {}
    derived foo() {
        derived d(base::foo());  // line 21
        return d;
    }
};

To facilitate the conversion from the base return type into a derived return type, I provide a private constructor in derived that handles this.

Compiling this on Centos 5.8 with gcc 4.1.2 produces the following error:

test.cpp: In member function ‘derived derived::foo()’:
test.cpp:6: error: ‘base::base(const base&)’ is protected
test.cpp:21: error: within this context

With gcc 4.6.1 and clang 2.9 on Linux Mint 12, the code compiles file, even with -Wall -Wextra, apart from an unused parameter warning for base's copy constructor.

I think this could be a compiler bug in gcc 4.1.2, but I was unable to find anything on the net. Has anyone seen this before?

I cannot update the compiler without massive pain. Is there a simple workaround other than making the copy constructor of the base class public?


EDIT I added base b; before line 21 in derived::foo(). In that case, gcc 4.6.1 and gcc 4.1.2 complain that the default ctor of base is protected, clang 2.9 compiles without warning. This is what David Rodríguez - dribeas said in his comment - the default ctor cannot be called on a different instance of base.


EDIT 2 The standard paragraph that seems to apply here is 11.5 [class.protected]. gcc 4.1.2 seems to be correct in refusing my code as incorrect and I wonder why gcc 4.6.1 and clang allow it. See my own answer for a preliminary solution.

like image 509
arne Avatar asked Jul 13 '12 14:07

arne


Video Answer


1 Answers

A workaround that you could try would involve creating a private constructor for derived that constructs it's base by calling the base function:

class derived : base {
    struct from_base_foo {};
    derived( from_base_foo ) : base( base::foo() ) {}
public;
    derived foo() {
       return derived( from_base_foo() );
    }
};
like image 113
David Rodríguez - dribeas Avatar answered Sep 20 '22 00:09

David Rodríguez - dribeas