Sacchan
Sacchan

Reputation: 377

Hiding a private overloaded virtual function?

I have a class hierarchy that works approximately like this:

class A 
{ 
protected: 
    virtual void f(int) = 0;
};

class B 
{ 
protected: 
    virtual void f(char*) = 0;
};

class DA : A 
{ 
private:
    virtual void f(int) override {}
};

class DB : public DA, B 
{ 
private:
    virtual void f(char*) override {}
};

When I try to compile with clang (or gcc, for that matter), it gives me the warning

<source>:22:18: warning: 'DB::f' hides overloaded virtual function [-Woverloaded-virtual]
    virtual void f(char*) override {}
                 ^
<source>:16:18: note: hidden overloaded virtual function 'DA::f' declared here: type mismatch at 1st parameter ('int' vs 'char *')
    virtual void f(int) override {}
                 ^

Which I understand, but should it really give that warning? After all, DB cannot even see the hidden function (which might even be named the same by coincidence).

If it wasn't private, I could use

using DA::f;

to clarify, of course, but the function is private, DB doesn't even know about it, and certainly shouldn't expose it.

Is there a way to fix this without deactivating that warning, i.e. telling the compiler that everything is designed as is intended?

Upvotes: 9

Views: 2041

Answers (3)

Jarod42
Jarod42

Reputation: 218193

A possible way to fix the warning is to duplicate code of DA::f inside DB:

class DB : public DA, B 
{
    virtual void f(int i) override
    {
         // copy implementation of DA::f(int) as you cannot do
         // return DA::f(i);
    }
private:
    virtual void f(char*) override {}
};

Demo

but a local pragma to remove warning seems more appropriate.

Upvotes: 0

Arne Vogel
Arne Vogel

Reputation: 6726

After all, DB cannot even see the hidden function (which might even be named the same by coincidence).

Accessibility and visibility are different concepts in C++. DA::f() is by default visible inside DB (and then hidden by DB::f()), but it is not accessible, because it is private inside DA, and DB is not a friend of DA. One could argue that hiding a function that is inaccessible is harmless, because it cannot be called anyway. However, the distinction between hidden and inaccessible can be significant because visible and inaccessible functions do participate in overload resolution. If db is an object of type DB, then what does db.f(0) do? If DA::f() is visible but inaccessible, it will be selected as best match and the compiler will emit a diagnostic because it is inaccessible and therefore cannot be called. If DA::f() is hidden, however, the compiler will select the overload that accepts a pointer instead, and treat the literal 0 as a null pointer.

Upvotes: 3

Sacchan
Sacchan

Reputation: 377

What I ended up doing (for now) is using composition instead of private inheritance. So my code currently looks like

class A 
{ 
protected: 
    virtual void f(int) = 0;
};

class B 
{ 
protected: 
    virtual void f(char*) = 0;
};

class DA  
{ 
    class D : A
    {
    private:
        virtual void f(int) override {}
    } d;
};

class DB : public DA
{ 
    class D : B
    {
    private:
        virtual void f(char*) override {}
    } d;
};

I'm not 100% happy with this, as the d members cause additional syntactial overhead, but at least it works without changing the public interface.

Upvotes: 0

Related Questions