Doing an experiment of translating .NET IL to C++ in a human readable fashion.
Here is the issue: C# allows you to resolve multiple interfaces with the same method name that only differ in return type. C++ doesn't seem to support this however making resolving two interfaces impossible using the vTable (or am i wrong?).
I've found a way to replicate the C# approach in C++ using templates but am wondering if there is a way that doesn't require templates that solves the same issue? Templates are verbose and I'd prefer not using them for every interface type if possible.
Here is the C++ version.
template<typename T>
class IMyInterface
{
public: short (T::*Foo_IMyInterface)() = 0;
};
template<typename T>
class IMyInterface2
{
public: int (T::*Foo_IMyInterface2)() = 0;
};
class MyClass : public IMyInterface<MyClass>, public IMyInterface2<MyClass>
{
public: MyClass()
{
Foo_IMyInterface = &MyClass::Foo;
Foo_IMyInterface2 = &MyClass::IMyInterface2_Foo;
}
public: virtual short Foo()
{
return 1;
}
private: int IMyInterface2_Foo()
{
return 1;
}
};
class MyClass2 : public MyClass
{
public: virtual short Foo() override
{
return 2;
}
};
void InvokeFoo(IMyInterface<MyClass>* k)
{
(((MyClass*)k)->*k->Foo_IMyInterface)();
}
void main()
{
auto a = new MyClass2();
InvokeFoo(a);
}
Here is the C# reference source the C++ one is based on.
interface IMyInterface
{
short Foo();
}
interface IMyInterface2
{
int Foo();
}
class MyClass : IMyInterface, IMyInterface2
{
public virtual short Foo()
{
return 1;
}
int IMyInterface2.Foo()
{
return 1;
}
}
class MyClass2 : MyClass
{
public override short Foo()
{
return 2;
}
}
namespace CSTest
{
class Program
{
static void InvokeFoo(IMyInterface k)
{
k.Foo();
}
static void Main(string[] args)
{
var a = new MyClass2();
InvokeFoo(a);
}
}
}
This C++ method doesn't work below but wish it did (its more what I'm going for).
class IMyInterface
{
public: virtual short Foo() = 0;
};
class IMyInterface2
{
public: virtual int Foo() = 0;
};
class MyClass : public IMyInterface, public IMyInterface2
{
public: virtual short Foo()
{
return 1;
}
private: int IMyInterface2::Foo()// compiler error
{
return 1;
}
};
class MyClass2 : public MyClass
{
public: virtual short Foo() override
{
return 2;
}
};
void InvokeFoo(IMyInterface* k)
{
k->Foo();
}
void main()
{
auto a = new MyClass2();
InvokeFoo(a);
}
The problem is that you can't overload based on return type alone.
See
The last stackoverflow thread points out overloading is possible using operators.
struct func {
operator string() { return "1"; }
operator int() { return 2; }
};
int main() {
int x = func(); // calls int version
string y = func(); // calls string version
double d = func(); // calls int version
cout << func() << endl; // calls int version
func(); // calls neither
}
You can't name them though, this would quickly turn into a mess to work with.
The argument list has to change. Victor Padureau suggested to use void return types and pass the type of value as reference to be set to a value in the method, that will work. You can also change the method name for the different types.
class my_interface
{
public:
virtual short foo_short() = 0;
};
class my_interface2
{
public:
virtual int foo_int() = 0;
};
class my_class : public my_interface, public my_interface2
{
public:
short foo_short() override
{
return 1;
}
int foo_int() override
{
return 1;
}
};
class my_class2 : public my_class
{
public:
virtual short foo_short() override
{
return 2;
}
};
void InvokeFoo(my_interface* k)
{
short result = k->foo_short();
std::cout << result << std::endl;
}
void main()
{
auto a = new my_class2();
InvokeFoo(a);
}
I have a solution that might work. It's not perfect, but it is a way to workaround the issue if you are porting.
Instead of calling int foo()
you can call void foo(int& out)
that way you are putting the return type in the calling part of the function.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With