Explicit Interface Method Implementation

In MC++, I can do the following: -

__gc __interface ICloneablePerson
{
Person* Clone();
};


public __abstract __gc class Person : public ICloneablePerson
{
private:
String* _name;

protected:
Person()
:_name(String::Empty)
{
}

Person(String* name)
:_name(name)
{
}

Person(Person* source)
:_name(source->_name)
{
}

public:
__property String* get_Name()
{
return _name;
}
};

public __gc class Student: public Person
{
private:
String* _id;
public:
Student(void)
:Person()
{
_id = String::Empty;
}

Student(String* name)
:Person(name)
{
_id = String::Empty;
}

Student(Student* source)
:Person(source)
{
this->_id = source->_id;
}

Student* Clone()
{
return new Student(this);
}

Person* ICloneablePerson::Clone()
{
return Clone();
}
};

public __gc class Test
{
public:
void static Start()
{
Person* person1 = new Student("David");
Student* person2 = new Student("Anthony");
Person* person3 = person1->Clone();
Student* person4 = person2->Clone();
}
};

However in CLi .Net 2.0, I can't. I mainly complains about the explicit implementation is not possible in CLi .Net 2.0.

Do you have any suggestion where I can archieve the same thing in new syntax.

Note: The code above returns the cloned object that is cast to a Person reference, if the object to be cloned is cast to a Person reference. It returns the cloned object as a Student reference if the object to be cloned is a Student reference.

Thank you.




Answer this question

Explicit Interface Method Implementation

  • DVD_SH

     aahkam wrote:
     Aleksandr Tokarev wrote:

    I've compiled your code with VS2005 (/clr:oldSyntax) everything works fine. There is explicit implementation even it native code.

    Which IDE do you use

    Yes, this compiled and run very well in MC++, but please try to do the same thing in new syntax under CLi 2.0, you will find it impossible to be done like that.

    #include "stdafx.h"

    using namespace System;

    interface class II1

    {

    public:

    void M1();

    };

    interface class II2

    {

    public:

    void M1();

    };

    ref class C: public II1, public II2

    {

    public:

    virtual void II1M1() = II1::M1

    {

    Console::WriteLine(__FUNCTION__);

    }

    virtual void II2M1() = II2::M1

    {

    Console::WriteLine(__FUNCTION__);

    }

    };

    int main(array<System::String ^> ^args)

    {

    Console::WriteLine(L"Hello World");

    C c;

    ((II1^)%c)->M1(); // Its works fine.

    ((II2^)%c)->M1(); // Its works fine.

    return 0;

    }

    I think in new sintax its more elegant and strong solution. It closes all questions.


  • Tej62007

    Aleksandr Tokarev wrote:

    einaros wrote:
    That seems like a language flaw on Managed C++'s part. From a C++ point of view, there's no way for the compiler to overload based on return type, which is what Clone is doing in the student class.

    You can override virtual function with equal signature and deffrent return type. The limitation for return type is: it should be derived from type of basic class return value. Its C++ standard, read B. Straustrup about.

    To overload is not to override. You cannot overload based on return value.



  • gon_no1

    It's not a bug. Evrythin works fine. Imagine you have to base interfaces with dublicated methods.

                         class IInterface1
                           {
                             public:
                                     virtual void M1()=NULL;
                           }

                         class IInterface2
                           {
                             public:
                                     virtual void M1()=NULL;
                           }
    How can you create one class derived from both interface And how can you override both M1 with different implementation The only way explicit overriding.

                           class A: public virtual IInterface1, public virtual IInterface2
                           {

                             public:

                                     virtual void IInterface1::M1(){Implementation 1}

                                     virtual void IInterface2::M1(){ Implementation 2}


                           }

     

    You can't call M1 directly from class A instance. The only way call this M1 type cast to a interface.

    class II1

    {

    public:

    virtual void M1()= 0;

    };

    class II2

    {

    public:

    virtual void M1()= 0;

    };

    class C: public virtual II1, public virtual II2

    {

    public:

    virtual void II1::M1()

    {

    cout<<__FUNCTION__<<endl;

    }

    virtual void II2::M1()

    {

    cout<<__FUNCTION__<<endl;

    }

    };

    int main()

    {

    C c;

    //c.M1(); //Uncomment you obtain ambiguous call Compiller says that he cannot undestend wich method to call.

    ((II1&)c).M1(); // Its works fine.

    }

     


  • Jacco Mintjes

    einaros wrote:

    aahkam wrote:
    Student* Clone()
    {
    return new Student(this);
    }

    Person* ICloneablePerson::Clone()
    {
    return Clone();
    }

    I find it unlikely for this to compile, first of all seeing as the compiler will be unable to see the difference between the two. As I said, one cannot overload based on return type.

    Drop the second definition, and you should be one step closer to your goal.

    The entire code can compile with VC++ 2005. Tested, I have no doubt on that. In the debug mode, it also seemed to be running exactly as I had expected from the source code. No down/upward type casting was needed.

    The code for the two Clone() methods is a reasonable case of selective overriding - not overloading.

    BTW, C# supports this type of overriding as well. However, in Java I'm not aware of any such language-level support up to JDK 1.5 (not sure about Java 6).

    Cheers,
    Henry



  • laurin1

    I've compiled your code with VS2005 (/clr:oldSyntax) everything works fine. There is explicit implementation even it native code.

    Which IDE do you use


  • Ronald&amp;#35;2

    My suspicion is that this is an unintentional side-effect of the bug that is seen. Consider, if you will, what would happen if you add another class to your puzzle, which inherits C. Next you go ahead and add a function which accepts a pointer to that derived class, and within that function you attempt to call the function M1. The result would be an ambiguous name resolution. That's inconvenient, and hardly seems intentional.

    As for the multiple inheritance itself, that's a completely different story. First of all, remember that public inheritance means an "is-a" relationship. Now if the derived class is-a entity of it's base classes, wouldn't it want the behavior to be the same no matter which of it's interfaces it's called through If the behavior differs, you'd have a schizophrenic object on your hands, which cannot make up it's mind if its one thing or the other. Normally this behavior would be implemented through RTTI and dynamic casts. The very notion to provide implementation on a per-class basis for ABC's goes against the very principle that is ABC. The class isn't an object, and provides no implementation, it just tells everyone what a derived class is going to implement.

    Also, the sheer fact that you actually need multiple inheritance to be able to call the overriden function which is declared in the derived class itself (see the note about ambiguity in my previous post), makes the whole extension completely absurd. This both from a language and object orientation perspective.

    A final note: your code doesn't compile on neither GCC nor Comeau, and the latter is (arguably) considered to be somewhat of a benchmark of how a C++ compiler should behave.

    Errors reported by the Comeau compiler:

    "ComeauTest.c", line 31: error: qualified name is not allowed
    virtual void II1::M1()
    ^

    "ComeauTest.c", line 39: error: qualified name is not allowed
    virtual void II2::M1()
    ^

    "ComeauTest.c", line 53: error: object of abstract class type "C" is not allowed:
    pure virtual function "II1::M1" has no overrider
    pure virtual function "II2::M1" has no overrider
    C c;



  • RyanB88

    Aleksandr Tokarev wrote:

    I've compiled your code with VS2005 (/clr:oldSyntax) everything works fine. There is explicit implementation even it native code.

    Which IDE do you use

    Yes, this compiled and run very well in MC++, but please try to do the same thing in new syntax under CLi 2.0, you will find it impossible to be done like that.



  • Siggy01

    That seems like a language flaw on Managed C++'s part. From a C++ point of view, there's no way for the compiler to overload based on return type, which is what Clone is doing in the student class.

  • Max Noyeke

     einaros wrote:
    That seems like a language flaw on Managed C++'s part. From a C++ point of view, there's no way for the compiler to overload based on return type, which is what Clone is doing in the student class.

    You can override virtual function with equal signature and deffrent return type. The limitation for return type is: it should be derived from type of basic class return value. Its C++ standard, read B. Straustrup about.

    Check this,

    class A

    {

    public:

    virtual A* Clone()

    {

    cout<<__FUNCTION__<<endl;

    return new A;

    }

    };

    class B: public A

    {

    public:

    B* Clone() //It's derived from A

    {

    cout<<__FUNCTION__<<endl;

    return new B;

    }

    };

    int main()

    {

    B b;

    A* a = &b;

    B* b1 = b.Clone();

    B* b2 = dynamic_cast<B*>(a->Clone());

    }

    Check this code it works even in native C++.

    Thats why you don't need explicit implementation.


  • Deltaxp

     einaros wrote:

    Errors reported by the Comeau compiler:

    "ComeauTest.c", line 31: error: qualified name is not allowed
      virtual void II1::M1()
                   ^

    "ComeauTest.c", line 39: error: qualified name is not allowed
      virtual void II2::M1()
                   ^

    "ComeauTest.c", line 53: error: object of abstract class type "C" is not allowed:
                pure virtual function "II1::M1" has no overrider
                pure virtual function "II2::M1" has no overrider
      C c;

     

    With CLi .Net 2.0 new syntax, the error reported is basically same as you got them here. But don't you think that Explicit Interface Methods Implementation a nice feature that will offer a great polymorphic design.

    With Explicit Interface Methods Implementation in this case we can have a cloned object automatically cast to a specific reference type as accorded to the reference type of source object to be cloned.

    In my example, All four objects are Students, but one (person3) will get the cloned Sudent object (person1) that is cast to Person reference automatically because that object (person1) is a Person reference.

    In the other case, one (person4) will get the cloned Sudent object (person2) that is cast to Student reference automatically because that object (person2) is a Student reference.

    This kind of polymorphism can be easily done with EIMI (Explicit Interface Methods Implementation), without it due to "a function cannot be overloaded by its return type" constraint, we can't achieve this.

    However, EIMI has a little difference than overloading a function by its return type.

     



  • axelfxxx

     HCTwinJava wrote:

    The entire code can compile with VC++ 2005. Tested, I have no doubt on that.  In the debug mode, it also seemed to be running exactly as I had expected from the source code.  No down/upward type casting was needed.

    The code for the two Clone() methods is a reasonable case of selective overriding - not overloading.

    I'm not too versed in the mechanics of C++/CLI, so this is new information to me. I neglected to mention that I was talking from a native point of view in this case.

    There's nothing in the ISO C++ standard, to which VC++ strives to conform, that indicates that this behaviour should be legal. As such, it surprises me that a construct such as the following compiles.

    class Foo
    {
    public:
        virtual Foo* doSomething() = 0;
    };

    class Bar : public Foo
    {
    public:
        Bar* doSomething();
        Foo* Foo::doSomething();
    };

    Now imagine trying to use this.

    Bar b;
    Foo* f = &b;
    f->doSomething();

    That should, granted how it works in C++/CLI, call (with pseudo qualification) Bar::Foo::doSomething(), and so it also does. However, if you then attempt to call

    b.doSomething();

    .. that will be ambiguous. Both Bar::doSomething and Bar::Foo::doSomething match the signature, and are equally accessible. Trying to compile it reveals that very fact.

    As a side note, but still an important one, this code doesn't compile with neither Comeau nor GCC (3.3.5). I can't help but wonder if this is a compiler bug.



  • wannabguru

    HCTwinJava wrote:
    einaros wrote:

    aahkam wrote:
    Student* Clone()
    {
    return new Student(this);
    }

    Person* ICloneablePerson::Clone()
    {
    return Clone();
    }

    I find it unlikely for this to compile, first of all seeing as the compiler will be unable to see the difference between the two. As I said, one cannot overload based on return type.

    Drop the second definition, and you should be one step closer to your goal.

    The entire code can compile with VC++ 2005. Tested, I have no doubt on that. In the debug mode, it also seemed to be running exactly as I had expected from the source code. No down/upward type casting was needed.

    The code for the two Clone() methods is a reasonable case of selective overriding - not overloading.

    BTW, C# supports this type of overriding as well. However, in Java I'm not aware of any such language-level support up to JDK 1.5 (not sure about Java 6).

    Cheers,
    Henry

    Yes, it runs fine with CLi/MC++ /clr:oldsyntax. I'm seeking a way to accomplish the same thing in CLi .Net 2.0 new syntax. It seems like I can't do that anymore in new syntax.



  • Larry Smith53314

    aahkam wrote:
    Student* Clone()
    {
    return new Student(this);
    }

    Person* ICloneablePerson::Clone()
    {
    return Clone();
    }

    I find it unlikely for this to compile, first of all seeing as the compiler will be unable to see the difference between the two. As I said, one cannot overload based on return type.

    Drop the second definition, and you should be one step closer to your goal.



  • Mark Hogan

    In the post start code. One method belongs to class, the second explicit implementation of interface method.

    Thats why when you call in class instance campiller knows which method to call. And when you cast to interface there is no insolubility.


  • Explicit Interface Method Implementation