Great implementations for pure virtual functions with the same name

Possible duplicate:
Inherit interfaces that share a method name

I have two base classes I1 and I2 with pure virtual functions void R() = 0; . I want the derived class IImpl inherit from I1 and I2 and have different implementations for I1::R() and I2::R() .

The code below compiles and works in MS VS 2005 and 2010. I compile with the Language Extension and at warning level 4. There are no warnings and errors.

I tried the same code in gcc 4.2. It does not compile. GCC reports an error:

 error: cannot define member function 'I1::R' within 'IImpl' 

My questions:

  • Why does this code work in MS VS and why does it not work in gcc?
  • Is the code standard C ++?
  • What is the correct way to implement it, so is it standard C ++ and compiles on VS and gcc?

Thanks!

 #include <stdio.h> class I1 { public: virtual void R() = 0; virtual ~I1(){} }; class I2 { public: virtual void R() = 0; virtual ~I2(){} }; class IImpl: public I1, public I2 { public: virtual void I1::R() { printf("I1::R()\r\n"); } virtual void I2::R() { printf("I2::R()\r\n"); } }; int main(int argc, char* argv[]) { IImpl impl; I1 *p1 = &impl; I2 *p2 = &impl; p1->R(); p2->R(); return 0; } 
+6
source share
4 answers

This code is non-standard, according to 8.3 / 1

The declaration identifier shall not be qualified, except for the definition of a member function (9.3) or a static data member (9.4) outside its class, ...

therefore, you cannot qualify the names of member functions when declaring / defining them inside a class. That is why it is not compiled by gcc.

MSVC seems to have a non-standard extension that allows such code. I assume that this was done for Managed Extensions for C ++, just as the explicit implementations of the interface were implemented there, and although it was deprecated a long time ago, it seems that the syntax is still supported.

The correct way to implement it is described by the link provided by BjΓΆrn Pollex.

+6
source

You can implement void R() only once in IImpl .

+1
source
 IImpl impl; I1 *p1 = &impl; I2 *p2 = &impl; p1->R(); p2->R(); 

That doesn't make sense to me. R() is a virtual method, so it doesn't matter, call it I1* or I2* , as long as the real object is IImpl . In addition, IImpl has two similar R() that you expect to call for impl.R() ? I am not familiar with the standard to quote it, but I am sure you are making a mistake. Correct me if I am wrong.

+1
source

@ Purple Giraffe

This is a response to the answer of the Purple Giraffe. It also eliminates some of the misunderstandings of late binding and MI, which are more flexible than Java inheritance.

therefore it doesn’t matter if you call it on I1 * or I2 * as long as the real object is IImpl.

 // interfaces class I1 { public: virtual void f () = 0; }; class I2 { public: virtual void f () = 0; }; // concrete implementations class C1 : public I1 { public: virtual void f () { cout << "C1::f()\n"; } }; class C2 : public I2 { public: virtual void f () { cout << "C2::f()\n"; } }; // putting both together class D : public C1, public C2 { }; template <class I> void f (I &i) { if(); // virtual call to I::f() } int main() { D d; f<I1> (d); // virtual call to I1::f(): prints C1::f() f<I2> (d); // virtual call to I2::f(): prints C2::f() } 

The call of a member function is always statically associated with the declaration of one function (here I1::f() and I2::f() ). At run time, a function called (by the "late binding" method) is the most derived handler (the technical term is "final") of this virtual function (here C1::f() and C2::f() ).

In any class there should be no more than one final redefinition of each pure virtual function. In a non-abstract class, there must be exactly one final redirector for each virtual function.

Now you see that I1::f() and I2::f() are different functions and that they are completely unrelated; but both have the same unqualified name and the same parameters, so they cannot be distinguished when overloaded. And if a qualified name is used ( d.I1::f() and d.I2::f() ), the call will be bound to the correct declaration, but virtuality will also be blocked (in this case, the definition of a pure virtual function must exist and will be called ) So the only way to call any function is what I did here: first make an lvalue of type I1 / I2 , and then make an unqualified call to .f() .

Side note. Such an explicit redefinition is not possible in Java, because MI is strictly limited, and redefinition follows different rules.

In addition, IImpl has two similar R () that you expect to call for impl.R ()?

What f() do you expect to call in df() ?

+1
source

Source: https://habr.com/ru/post/900265/


All Articles