Link to home
Start Free TrialLog in
Avatar of jochemspek
jochemspekFlag for Netherlands

asked on

re-implementing virtual assignment operator of a templated class

Dear all,

I have an issue with re-implementing the assignment operator of
a base class, of which the derived class is templated.

the code:

#include <string>
#include <iostream>
#include <iomanip>
#include <sstream>
#include <exception>

using namespace std;

class AbstractProperty {
public:
    virtual string getValue() = 0;
    virtual void setValue( string value ) = 0;
    virtual AbstractProperty & operator = ( AbstractProperty & rhs ) = 0;
};

template< class T >
class Property : public AbstractProperty {
public:
    Property( T value ):
        m_value( value ){
    }

    string getValue(){
        stringstream ss;
        ss << m_value;
        return( ss.str() );
    }
    void setValue( string value ){
        stringstream ss;
        ss << value;
        ss >> m_value;
    }
    AbstractProperty & operator = ( AbstractProperty & rhs ){
        try{
            Property & p = dynamic_cast<Property & >( rhs );
            this->m_value = p.m_value;
        }
        catch( exception & e ){
            cout << "eek ! a " << e.what( ) << endl;
        }
        return( * this );
    }

private:
    T m_value;
};

void main( void ){
    int i1 = 1;
    int i2 = 2;

    float f = 0.5;

    Property<int> Pi1( i1 );
    Property<int> Pi2( i2 );

    Property<float> Pf( f );

    Pi2.setValue( "3" );
    Pf.setValue( "0.25" );

    cout << "Pi1: " << Pi1.getValue() << endl;
    cout << "Pi2: " << Pi2.getValue() << endl;
    cout << "Pf: " << Pf.getValue() << endl;

    Pi1 = Pf; // works, but with a Bad Dynamic (as expected)
    Pi1 = Pi2; // doesn't compile, because
                //  unresolved external symbol "public: virtual class AbstractProperty
                // & __thiscall AbstractProperty::operator=(class AbstractProperty &)"

    cout << "Pi1: " << Pi1.getValue() << endl;

}

What I *really* don't understand, is why the two Property<int> instances
being assigned results in an unresolved function, shouldnt the two instances
compare as two Property<int> classes, and thus be implemented by the template ?
it's not a matter of the argument to the assignment operator not being constant,
Ive checked.

any input is appreciated,

Jonathan
ASKER CERTIFIED SOLUTION
Avatar of evilrix
evilrix
Flag of United Kingdom of Great Britain and Northern Ireland image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jochemspek

ASKER

@elvirix, thanks, but I still don't understand why the given code doesn't compile,
why doesnt the compiler resolve the assignment operator to be that of the Property<int> class ?

J
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
ah. I think I got it, I'm confusing the situation where :

class A{
          virtual A & operator = ( A & a ) = 0;
};

class B : public A {
          virtual A & operator = ( A & a ){
               cout << " here ";
           }
}

B * b1 = new B();
B * b2 = new B();

* b1 = * b2;

in this situation, the assignment operator in B is called, even when
b1 and b2 are cast to A *..

J
>> in this situation, the assignment operator in B is called

In function `B::operator=(B&)':
x.cpp:53: undefined reference to `A::operator=(A&)'
collect2: ld returned 1 exit status
make: *** [xprog] Error 1
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
@evilrix:

sorry, that was from the top of my mind,
here's what i meant, which builds & runs..

class A{
public:
          virtual A & operator = ( A & a ) = 0;
};

class B : public A {
public:
          virtual A & operator = ( A & a ){
               B & b = static_cast< B & >( a );
               cout << " do something b'ish here ";
             return( * this );
           }
};

void main( void ){

      B * b1 = new B();
      B * b2 = new B();

      * ( A * )b1 = * ( A * )b2;
}

this works, but is it legal ?

@phoffric: thanks, how do you reckon does 2) relate to my example ?

J
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
SOLUTION
Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of phoffric
phoffric

@evilrix - LOL - What makes it heavier is that usually when something doesn't compile or build, the examples are there to show just that, and there are comments that indicate the problem. If I were just reading it and not trying the example stated, I would have thought that this would build. Maybe I'm doing something wrong. (I usually like to try out new things to help let it sink in. For some reason, I have never come across this item about trying to inherit the = operator. (Or maybe I saw it and thought "no problem".)
@evilrix - does "just like me" apply to "a former member of the C++ standards council" as well as "a Brit"?
>> does "just like me" apply to "a former member of the C++ standards council" as well as "a Brit"?
Muhahaha -- I wish. No just the Brit part :)

The reason the example code doesn't build is because the function bodies are missing. You'll not thought that even with the function bodies in D it still would build unless you also implement them in B.
struct B {
        virtual int operator= (int); // { return 0; }
        virtual B& operator= (const B&); // { return *this; };
};
struct D : B {
   virtual int operator= (int) { return 0; }
        virtual D& operator= (const B&) { return *this; };
};
D dobj1;
D dobj2;
B* bptr = &dobj1;

void f() {
        bptr->operator=(99);    // calls D::operator=(int)
        *bptr = 99;             // ditto
        bptr->operator=(dobj2); // calls D::operator=(const B&)
        *bptr = dobj2;          // ditto
        dobj1 = dobj2;          // calls implicitly-declared
                                // D::operator=(const D&)
}
// I add main in order to build
int main()
{
}

Open in new window

Ahh so! So that's how you work this C++ Language Spec thingy :)
I was so blind-sided by the question that I didn't even consider this intuitive, oh so clear, obvious answer (thanks to you).

Sorry jochemspek, I didn't mean to go off on a tangent that doesn't help you.