2

Suppose the code below:

Base.h

template <class T>
class Base
{
public:
    virtual void func(T value) {}
};

Derived.h

class Derived : public Base<Type1>
              , public Base<Type2>
{
public:
    void func(Type1 object) override {}
};

Basically I have a templated class with a member function that takes the argument of the template type. The derived class derive from the base with two different class type, and override the function of one of them.

With the Clang compiler, it would generate a hides overloaded virtual functions warning, which is actually intended here, i.e. I do not need Base2::func(float) in the derived class.

I am aware that by appending -Wno-overloaded-virtual to the compiler flags would mute this warning but I'm not sure that's the safe thing to do, as in other cases this warning may be valid.

In my project I have thousands of this case (i.e. many derived classes with different class types). Are there any good suggestion over it so the warning wouldn't be present for this situation but keep it for others?

Wayee
  • 379
  • 1
  • 5
  • 17
  • Three's [this answer](https://stackoverflow.com/a/20146621/817643). I think it's a quality dup on account of that. Would you say so? – StoryTeller - Unslander Monica Sep 26 '18 at 10:05
  • Possible duplicate of [c++ overloaded virtual function warning by clang?](https://stackoverflow.com/questions/18515183/c-overloaded-virtual-function-warning-by-clang) – VLL Sep 26 '18 at 10:08
  • @StoryTeller @Ville-Valtteri I saw that post but actually it's not a duplicate, as here I do want to hide the overloads. So `using Base1::func` is of no help here. – Wayee Sep 26 '18 at 10:36
  • @Wayee - I linked to a specific answer. To get the best of SO one must often read beyond the accepted answer. – StoryTeller - Unslander Monica Sep 26 '18 at 10:38
  • This may be a design problem. If the function isn't needed for this case, why is it there? That base class might be a mishmash of what should be two distinct bases. – Pete Becker Sep 26 '18 at 11:20
  • @Pete Becker, actually in my real case, the base classes are the instances of the observer pattern. The base class of the observer defined some generic functions which are specifically implemented in each observer. Then the user class derives from several different observers. To answer your question, the function needs to be there in the base class because it's going to be used in most cases. But in some occasional cases I just want to override this function for some observers but not the others. Hope this is clear. – Wayee Sep 26 '18 at 11:37
  • @Wayee -- that misses my point. If it's only needed in some (or most) cases, that suggests that there are two distinct base classes, not one. One base class should that function and one shouldn't. The former might well be derived from the latter. – Pete Becker Sep 26 '18 at 11:41
  • @Story Teller: The specific answer you posed would indeed get rid of the warning. But I would need to do it in thousands of different places. Is there a more generic way? – Wayee Sep 26 '18 at 11:44
  • Define "thousands of places"? The pragma can be set on the whole file, and not per function. If that still isn't generic enough, I second Pete. You have a deeper issue you need to resolve. You want to say "these thousands of functions are okay, but these thousands of functions are not". How exactly should any automatic tool tell them apart without your help? – StoryTeller - Unslander Monica Sep 26 '18 at 11:51
  • @Story Teller: Could you have a look of my edited question? It now better shows the real use case. The base class in the real problem is actually one template class. And in the derived ones I inherit from it with different template types, and override the virtual member only for some types, but not all. – Wayee Sep 26 '18 at 14:25
  • @It doesn't change the suggested solution at all. The hiding happens in the deriving class, not the base. So it makes no difference if the base is a template specialization. – StoryTeller - Unslander Monica Sep 26 '18 at 15:01
  • Providing `private: using Base::func;` in the derived class will squelch the warning, and explicitly show the intent of hiding the function. – Eljay Sep 26 '18 at 15:58

2 Answers2

3

The safe way is to unhide the method is with using:

class Derived : public Base1, public Base2
{
public:
    using Base2::func;
    void func(int) override {}
};

With that following works as expected:

Derived d;
d.func(4.2f); // call correctly Base2::func(float) and not Derived::func(int).

To silent the warning for intentional hiding, there are still the compiler specific way:

class Derived : public Base1, public Base2
{
public:

#pragma clang diagnostic push
# pragma clang diagnostic ignored "-Woverloaded-virtual"
    void func(int) override {}
#pragma clang diagnostic pop
};

And then:

Derived d;
d.func(4.2f); // call Derived::func(int).
Jarod42
  • 203,559
  • 14
  • 181
  • 302
  • The OP doesn't want to unhide it. Their hiding is intentional. This answer can and will alter results of overload resolution. So how is this an answer to the question? – StoryTeller - Unslander Monica Sep 26 '18 at 10:07
  • @StoryTeller: Missed one sentence from OP :(, amended to give "solution". – Jarod42 Sep 26 '18 at 10:17
  • The first half of this answer does not solve the situation in the question, as we intend to hide the overloads. The second half would work, but as mentioned in the question we got thousands of uses of this situation, adding `#pragma` for each of them won't be ideal. I'm more thinking if we have a design fault for this case. – Wayee Sep 26 '18 at 10:40
  • If you have always the same 2 bases, you can create that intermediate class from which other inherit from. Then only that one requires the `#pragma`. – Jarod42 Sep 26 '18 at 13:39
0

I actually wouldn't use multiple inheritance in this case, since it is still possible to call Base2::func() with the help of a type conversion (e.g. convert Derived * implicitly or explicitly to a Base2 *), despite it being hidden and not in scope of Derived.

Instead, I would do

class Derived : public Base1
{
   private:
        Base2 base2;

   public:
      void func(int) override {};
};

which will mean that func(float) is not within the scope of Derived at all. Only member functions of Derived (or friends) would be able to call base2.func(some_float).

This does prevent implicit conversion of a Derived * to a Base2 * (or Derived & to a Base2 &). I'd argue that if you need such implicit conversions, then your design is broken, since that would also permit (indirectly) calling Base2::func() for an instance of Derived. Which, presumably if you want it hidden, you wish to avoid ...... Generally speaking, if you find yourself in a contradictory discussion in design (you want X, but achieving X has an unwanted effect Y) that's a sign of a design flaw.

Peter
  • 35,646
  • 4
  • 32
  • 74
  • The example in the question was largely simplified and abstracted from the real use case. Please see my comment to answer @Pete Becker below the question. I'm aware this might be a design issue, but I'm out of ideas about how to solve it. – Wayee Sep 26 '18 at 11:41
  • @Wayee - I agree with Pete Becker. He's making the same point I am about your design being flawed. We've offered different options to address that design concern, but our point is the same - the problem is your design. Shutting up the compiler is not a solution. Redesign in a manner that does away with the concern is. – Peter Sep 26 '18 at 13:56