9

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?

Sacchan
  • 377
  • 3
  • 9
  • take a look to this [link](https://stackoverflow.com/questions/357307/how-to-call-a-parent-class-function-from-derived-class-function) – Mquinteiro Jul 05 '17 at 15:08
  • Is there any reason you want to use private virtual methods? If you make `f` a non-virtual method in `DA` the warning is removed. – jodag Jul 05 '17 at 15:15
  • @jodag: I cannot make f non-virtual, it overrides a function from A. And it is private since A is inherited privately. – Sacchan Jul 05 '17 at 15:28
  • @Mquinteiro: Unless I'm mistaken, that link has nothing to do with my question, excepting the fact that the accepted answer also mentions multiple inheritance – Sacchan Jul 05 '17 at 15:31
  • 4
    One can override a private virtual function. So the warning may be justified. –  Jul 05 '17 at 15:53
  • @manni66 Interesting, thank you. I agree that in that case, the warning is justified, though I still would like a way to tell the compiler that this is intentional – Sacchan Jul 05 '17 at 15:56
  • One solution could be to move the implementation of `void f(char*)` to an intermediary class between `B` and `DB`. Then the compiler correctly understands what you are trying to do. Not sure if this works in your situation. – bitmask Jul 05 '17 at 16:01
  • Have a look at this link: https://useyourloaf.com/blog/disabling-clang-compiler-warnings/ Clear example of what you may be looking for, – Dr t Jul 05 '17 at 16:02
  • @Drt: As I stated in the question, I specifically want to avoid deactivating compiler warnings. – Sacchan Jul 05 '17 at 16:06
  • 1
    Your question ended with: " i.e. telling the compiler that everything is designed as is intended?" Which i do believe is answered at the link I pointed out. The Clang user manual states essentially the same thing. You disable only for one line of code which is the really only practical way for you to "Tell the compiler" something... and the instructions are in the user manual... – Dr t Jul 05 '17 at 16:17

3 Answers3

3

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.

Arne Vogel
  • 6,346
  • 2
  • 18
  • 31
  • True enough. In my real example (which is quite a bit more involved), the objects in the two signatures cannot actually be interpreted as each other, so it isn't quite as harmful – Sacchan Jul 05 '17 at 16:52
0

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.

Sacchan
  • 377
  • 3
  • 9
0

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.

Jarod42
  • 203,559
  • 14
  • 181
  • 302