C++: pure virtual assignment operator
Asked Answered
T

3

6

why if we have pure virtual assignment operator in a base class, then we implement that operator on the derived class, it give linker error on the base class?

currently I only have the following explanation on http://support.microsoft.com/kb/130486 , it said that the behavior is by design since normal inheritance rules does not apply.

it is not clear for me, why is it generate linker error by design? can someone give me more clear explanation about this?

edit: added my simplified code of which the error occured:

class __declspec(dllexport) BaseClass {
public:
    int memberA;
    virtual BaseClass& operator=(const BaseClass& rhs) = 0;
};

class __declspec(dllexport) DerivedClass : public BaseClass {
public:
    int memberB;
    DerivedClass():memberB(0) {}
    virtual BaseClass& operator=(const BaseClass& rhs) {
        this->memberA = rhs.memberA;
        this->memberB = 1;
        return *this;
    }
};

int main(void)
{
    DerivedClass d1;
    DerivedClass d2;

    BaseClass* bd1 = &d1;
    BaseClass* bd2 = &d2;

    *bd1 = *bd2;
}

the code will compile with no errors without __declspec(dllexport) and/or without pure virtual operator= declaration on base class.

without __declspec(dllexport) after assignment of *bd1 = *bd2;, d1::memberB is 1, but with __declspec(dllexport) d1::memberB is left unchanged

with __declspec(dllexport), and without pure virtual declaration, after assignment of *bd1 = *bd2;, d1::memberB is left unchanged

Tattered answered 21/9, 2010 at 13:54 Comment(6)
might be helpful to post some example code along with the full linker error MSVC is spitting outScan
FWIW, Item 33 of Scott Meyers' More Effective C++ ("Make Non-Leaf Classes Abstract") covers how to deal with operator= in an inheritance hierarchy.Logue
@necrolis: example code is on the given link aboveTattered
@uray: Ideally, questions on SO will be self-contained, since one purpose is to establish a knowledge base for those who come after us. I've seen stuff on microsoft.com go away over time.Narrowminded
@uray: apart from what David Thornley mentioned, sometimes MS code its self can contain errors, or just be so generic that it doesn't apply too well too your specific situation. I was inferring that the example be from your code, which might have a bug MS's doesn't.Scan
question edited (added example code)Tattered
D
7

From section 12.8 of the standard:

13 The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Each subobject is assigned in the manner appropriate to its type:

— if the subobject is of class type, the copy assignment operator for the class is used (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);

The subclass is using the implicitly-defined copy assignment operator, and there is no definition of the base class's copy assignment operator, but it is declared, so you get a link error instead of a compilation error.

Demasculinize answered 21/9, 2010 at 14:9 Comment(4)
I think he's talking about operator=, not the copy constructor. For the copy ctor -- virtual, and pure virtual should be an immediate compiler error as it really makes no sense for them.Stephanestephani
His link is about operator= and that is what my post is about.Demasculinize
From the OP then we implement that operator on the derived class I'm going to say that he has an explicit copy assignment operator in the child (not implicit which your answer would cover correctly), and no indication that it is or isn't calling the parent (pure virtual) copy assignment.Treat
True, but in the comments, he did explicitly point Necrolis to the link. Even still, if he defined A &operator= (A&) in B, the assignment would still call the implicit version, since both operands are of type B, and "a base class copy assignment operator is always hidden by the copy assignment operator of a derived class" (12.8.10).Demasculinize
S
7

operator= is not inherited. Your code is meaningless in C++, so compilers are free to issue any error they want for it.

From the KB article you pointed to: http://support.microsoft.com/kb/130486

Since operator= is not inherited, any declaration of operator= in the base class is unused and unnecessary. Do not declare the operator= in the base class.

It's probably just a side-effect of how they compile, and they are just letting you know that they don't consider it a bug, so there is no need to fix it. "By design" doesn't necessarily mean that they specifically decided that this linker error is the right error message to give for this situation -- the code is wrong, you get an error, so from their point of view -- they're done.

Stephanestephani answered 21/9, 2010 at 14:4 Comment(1)
The OP's KB article. I will udpateStephanestephani
D
7

From section 12.8 of the standard:

13 The implicitly-defined copy assignment operator for class X performs memberwise assignment of its subobjects. The direct base classes of X are assigned first, in the order of their declaration in the base-specifier-list, and then the immediate non-static data members of X are assigned, in the order in which they were declared in the class definition. Each subobject is assigned in the manner appropriate to its type:

— if the subobject is of class type, the copy assignment operator for the class is used (as if by explicit qualification; that is, ignoring any possible virtual overriding functions in more derived classes);

The subclass is using the implicitly-defined copy assignment operator, and there is no definition of the base class's copy assignment operator, but it is declared, so you get a link error instead of a compilation error.

Demasculinize answered 21/9, 2010 at 14:9 Comment(4)
I think he's talking about operator=, not the copy constructor. For the copy ctor -- virtual, and pure virtual should be an immediate compiler error as it really makes no sense for them.Stephanestephani
His link is about operator= and that is what my post is about.Demasculinize
From the OP then we implement that operator on the derived class I'm going to say that he has an explicit copy assignment operator in the child (not implicit which your answer would cover correctly), and no indication that it is or isn't calling the parent (pure virtual) copy assignment.Treat
True, but in the comments, he did explicitly point Necrolis to the link. Even still, if he defined A &operator= (A&) in B, the assignment would still call the implicit version, since both operands are of type B, and "a base class copy assignment operator is always hidden by the copy assignment operator of a derived class" (12.8.10).Demasculinize
E
2

In the example code:

class A
{
public :
   // To workaround LNK2001, comment the following line.
   virtual const A& operator=( const A& f ) = 0;
};

class B : public A
{
public :
   const A& operator=( const A& g ) {return g;}
};

B aB1, aB2;

int /*void*/ main( void )
{
   aB2 = aB1;
}

the line aB2 = aB1 does not call const A& B::operator=(const A&), but instead calls the automatically supplied B& operator=(const B&); which in turn uses the assignment operator for assigning the base portion of the class. But when it comes to linking, it turns out that that was never implemented.

Empress answered 21/9, 2010 at 14:9 Comment(3)
The assignment operator has been overriden. Like declaring any constructor (non-template) effectively deactivate the implicitly defined default constructor and copy constructor, declaring any operator= (non-template) deactivate the implicitly defined assignment operator.Bestraddle
@Matthieu: Does that qualify as copy assignment? And after all, struct X { X& operator=(int);}; does not prevent me from assigning one X to another which it should, if any overload of operator= disabled the default one. - Similarly, any constructor does not deactivate the copy constructor, only a valid user-defined copy constructor.Empress
you're right, yet when using B& operator=(A const&) this version is called instead of the default one (at least with VC++10)... now I am all confused and it's too late for me to look into this...Bestraddle

© 2022 - 2024 — McMap. All rights reserved.