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