arne
arne

Reputation: 4674

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.

Upvotes: 6

Views: 1398

Answers (2)

arne
arne

Reputation: 4674

My preliminary solution is to make base's copy ctor public. To disallow copying of derived instances using the copy ctor of base, the inheritance needs to be protected instead of public. The resulting classes now look like this:

class base {
protected:
    base() {}
public:
    base (base const &other) {}
protected:
    base foo () {
        base ret;
        return ret;
    }
};

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

Upvotes: 0

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() );
    }
};

Upvotes: 1

Related Questions