Home > OS >  C Specific override of template class member function
C Specific override of template class member function

Time:06-28

I would like to have a class that implement multiple interfaces of same template class as follow:

template<typename T>
class Interface
{
public:
    virtual void foo(const T&) = 0;
    virtual void bar() = 0;
};

class A{};
class B{};

class Derived : public Interface<A>, public Interface<B> { /* ... */ };

Here class Derived would have methods

void Derived::Interface<A>::foo(const A&)
void Derived::Interface<B>::foo(const B&)
void Derived::Interface<A>::bar()
void Derived::Interface<B>::bar()

The first 2 are no problem, but the last 2 are ambiguous.
In call context it is ok for me to do:

int main()
{
    Derived d;
    d.Derived::Interface<A>::bar();
    d.Derived::Interface<B>::bar();
}

The problem is overriding specific methods.
I thought I could just write:

class Derived : public Interface<A>, public Interface<B>
{
public:
    inline void Interface<A>::bar() override { /* ... */ }
    inline void Interface<B>::bar() override { /* ... */ }
};

But the linker says it does not find method definition for methods referenced in main: d.Derived::Interface<A>::bar() & d.Derived::Interface<A>::bar().

I succeeded to do it, but I needed to add a "default" method override:

class Derived : public Interface<A>, public Interface<B>
{
public:
    inline void bar() override {}
};

void Derived::Interface<A>::bar() { /* ... */ }
void Derived::Interface<B>::bar() { /* ... */ }

EDIT: with MSVC compiler the above code compile, but with clang/gcc you need to specify template<> in front of bar method specializations.

Now, the main compile and run correctly as intended.

QUESTION: Is it possible to not add this "default" override ? Because I will never need to just call d.bar() and thus the implementation is empty and might lead to confusion.

Thank you ☺

CodePudding user response:

A similar situation is discussed in detail in one of the Stroustrup's books. His solution is to "rename" one or both functions this way:

class InterfaceA : public Interface<A> {
   void bar() override { barA(); }
   virtual void barA() = 0; 
      // or call Interface<A>::bar() if it has an implementation
};

class InterfaceB : public Interface<B> {
   void bar() override { barB(); }
   virtual void barB() = 0;
      // or call Interface<B>::bar() if it has an implementation
};

Now when you call bar through an Interface<A> pointer or reference, it will call Interface<A>::bar, which will call barA, which will call whatever override of barA your concrete class has. Same about Interface<B>. Derived "renames" bar inherited from Interface<A> to barA, so if you have a Derived pointer or reference, you need to call that. Calls to bar will be ambiguous.

CodePudding user response:

Thanks to n. 1.8e9-where's-my-share m. I realize I was not overriding bar method but specializing the template (also MSVC not seeing that as an error ...)

What I wanted to achieve is:

#include <iostream>
#include <string>

template<typename T>
class Interface
{
public:
    void bar();
};

class A
{
public:
    static const std::string& msg()
    {
        static std::string aMsg = "A";
        return aMsg;
    }
};

class B
{
public:
    static const std::string& msg()
    {
        static std::string bMsg = "B";
        return bMsg;
    }
};

class Derived : public Interface<A>, public Interface<B>
{
};

template<> void Derived::Interface<A>::bar() { std::cout << A::msg() << std::endl; }
template<> void Derived::Interface<B>::bar() { std::cout << B::msg() << std::endl; }

int main()
{
    Derived d;
    d.Interface<A>::bar();
    d.Interface<B>::bar();
}

The output is:

A
B

Now I won't have a bar method doing nothing and if there is no specialization of bar method for Derived class there will be a link error forcing the developer to implement/specialize the method. Thanks

  • Related