#include <cstdlib>
#include <iostream>
usingnamespace std;
#define QUANTITY 5
class Parent
{
protected:
int ID;
public:
virtualvoid showID() { cout << "Parent::showID()" << endl << endl; }
virtualvoidoperator= ( const Parent &p) { this->ID = p.ID; cout << "Parent::operator=() invoked."<< endl << endl; }
};
class Child : public Parent
{
public:
Child() { this->ID = rand(); }
void showID() { cout << "Child::showID() -- ID is " << this->ID << endl << endl; }
voidoperator= ( const Child &p) { this->ID = p.ID; cout << "Child::operator=() invoked."<< endl << endl; }
};
Parent *array[QUANTITY];
int main()
{
for (int i=0; i < QUANTITY; i++)
array[i] = new Child;
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
*array[2] = *array[3];
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
for (int i=0; i < QUANTITY; i++)
delete array[i];
return 0;
}
The output of the code:
Child::showID() -- ID is 1804289383
Child::showID() -- ID is 846930886
Child::showID() -- ID is 1681692777
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1957747793
Parent::operator=() invoked.
Child::showID() -- ID is 1804289383
Child::showID() -- ID is 846930886
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1957747793
Question:
Why is Parent::operator= invoked instead of Child::operator= ..?
Isn't it already declared virtual and hence would be overridden..?
I need to invoke Child::operator= instead. How to achieve this?
I apparently you only hide the Parent::operator=.
Try using using Parent::operator=; inside Child.
EDIT: tried it here http://ideone.com/OfZlGi, but need to have an account to edit :-/
Sadly I have no time currently, because I'm running a build of my projects which is about to be ready in the next seconds :-/
Why is Parent::operator= invoked instead of Child::operator= ..?
The main issue is that the Child::operator= has a different signature than the Parent::operator=, so the Child::operator= is not virtual and doesn't override the Parent version. It simply hides it when you're dealing with objects who's static type is Child.
Isn't it already declared virtual and hence would be overridden..?
For a function be overriden, the parameter list in the overriding function must be identical.
I need to invoke Child::operator= instead. How to achieve this?
Cast to the correct type before invoking the operator. You probably need to consider whether a Child being assigned to a Parent is meaningful and vice versa. operator= of a derived class typically calls the base class operator=.
I am not sure, but I think that
virtual void operator= ( const Parent &p)
is not ovverriden by virtual void operator= ( const Child &p)
if you want to override your customized operator= in Child perhaps you have to declare a void operator= ( const Parent &p)
Question: how did you be able to compile this program? I remember that when I tried to do a thing like that my compiler (I use gcc) returned me an error (that says that you are declaring an already implicitly declared function).... (this why I never more tried to overload operator= )
#include <cstdlib>
#include <iostream>
usingnamespace std;
#define QUANTITY 5
class Parent
{
protected:
int ID;
public:
int getID() { returnthis->ID; }
virtualvoid showID() { cout << "Parent::showID()" << endl << endl; }
virtualvoidoperator= (Parent &p) { this->ID = p.ID; cout << "Parent::operator=() invoked."<< endl << endl; }
};
class Child : public Parent
{
public:
Child() { this->ID = rand(); }
void showID() { cout << "Child::showID() -- ID is " << this->ID << endl << endl; }
voidoperator= (Parent &p) { this->ID = p.getID(); cout << "Child::operator=() invoked."<< endl << endl; }
};
Parent *array[QUANTITY];
int main()
{
for (int i=0; i < QUANTITY; i++)
array[i] = new Child;
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
*array[2] = *array[3];
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
for (int i=0; i < QUANTITY; i++)
delete array[i];
return 0;
}
The output of this code:
Child::showID() -- ID is 1804289383
Child::showID() -- ID is 846930886
Child::showID() -- ID is 1681692777
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1957747793
Child::operator=() invoked.
Child::showID() -- ID is 1804289383
Child::showID() -- ID is 846930886
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1714636915
Child::showID() -- ID is 1957747793
Questions:
1). Program output seems fine. The code is correct, right..?
2). Meanwhile, one problem is:- I have to remove the keyword const from the argument of voidoperator= (Parent &p)
If I use voidoperator= (const Parent &p) instead, then this error occurs during compilation:
error: passing 'const Parent' as 'this' argument of 'int Parent::getID()' discards qualifiers [-fpermissive]
I don't know why and don't understand the error message.
Could anyone explain this..?
#include <cstdlib>
#include <iostream>
usingnamespace std;
#define QUANTITY 5
class Parent
{
protected:
int ID;
public:
int getID() const { returnthis->ID; }
virtualvoid showID() { cout << "Parent::showID()" << endl << endl; }
virtualvoidoperator= (const Parent &p) { this->ID = p.ID; cout << "Parent::operator=() invoked."<< endl << endl; }
};
class Child : public Parent
{
public:
Child() { this->ID = rand(); }
void showID() { cout << "Child::showID() -- ID is " << this->ID << endl << endl; }
voidoperator= (const Parent &p) { this->ID = p.getID(); cout << "Child::operator=() invoked."<< endl << endl; }
};
Parent *array[QUANTITY];
int main()
{
for (int i=0; i < QUANTITY; i++)
array[i] = new Child;
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
*array[2] = *array[3];
for (int i=0; i < QUANTITY; i++)
array[i]->showID();
for (int i=0; i < QUANTITY; i++)
delete array[i];
return 0;
}
This works, its output is exactly same with the output of code 2 above.
Questions:
1). Could I say that this approach is safer than using dynamic_cast? dynamic_cast seems a bit indeterministic during run-time.. (that's why we use the try... catch... for dynamic_cast)
2). We pass argument by reference (not by value) in the operator argument.
Why must we use voidoperator= (const Parent &p) rather than voidoperator= (const Parent p) ?
I tested it, both works, both produce same output.
But in this case, is reference more preferable in the argument, why?
1). Is this approach safer than using dynamic_cast?
No.
dynamic_cast seems a bit indeterministic during run-time.. (if save enough why you put try... catch...)
In this simple case dynamic cast isn't necessary, but suppose you added a data member to child? How do you know if it's safe to access that member for p in your operator=? What if the actual type of p is Parent and it has no such member?
I come across this guideline about casting in C++.
1). Avoid casts whenever practical, especially dynamic_cast in performance-sensitive code.
If a design requires casting, try to develop a cast-free alternative.
2). When casting is necessary, try to hide it inside a function. Clients can then call the function instead of putting casts in their own code.
3). Prefer C++ casts to old-style casts. They are easier to see, and they are more specific about what they do.
Above are extracted from Item 27 (page123) the book:
Title: Effective C++ Third Edition
Author: Scott Meyers
ISBN-13: 978-0-321-33487-9
ISBN-10: 0-321-33487-6
Is this true? If yes, I need to rethink my casting strategy above..
> If a design requires casting, try to develop a cast-free alternative.
Yes.
> Avoid ... especially dynamic_cast in performance-sensitive code.
> Is this true? If yes, I need to rethink my casting strategy above..
A dynamic_cast has a run-time overhead;
Given a pointer to an object of a polymorphic class, a cast to a pointer to another base subobject of the same derived class object can be done using a dynamic_cast. In principle, this operation involves finding the virtual function table, through that finding the most-derived class object of which the object is part, and then using type information associated with that object to determine if the conversion (cast) is allowed, and finally performing any required adjustments of the this pointer. In principle, this checking involves the traversal of a data structure describing the base classes of the most derived class. Thus, the run-time cost of a dynamic_cast may depend on the relative positions in the class hierarchy of the two classes involved.
- Technical report on C++ performance (TR-18015)
Measure it on your specific implementation; and see if it is affordable for you or not. As far as performance goes, a single measurement is worth more than a thousand opinions.
For most programs, numbers like these (single-level casts) would be more than acceptable:
1000000 dynamic_down_cast took 60 msecs
1000000 dynamic_cross_cast took 80 msecs
1000000 dynamic_down_cast_virtual took 90 msecs
1000000 dynamic_cross_cast_virtual took 100 msecs