Overloading the assignment operator for a pointer, is it possible?

Is it at all possible to overload the assignment operator for a pointer? A pointer to a base class can be made to point to a derived class, but a pointer to a derived class cannot be made to point to an object of its base class.

ex.
let say that we have two classes, rectangle and square
square is derived from rectangle

in C++ you can

rectangle rec;
square squ;

rectangle *recP = □

but you cannot

square *squP = &rec;
justinvoelsAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

oleberCommented:
you can alway cast

square *squP = (square *)&rec;

but notice that is dangerous to do it.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
oleberCommented:
I would consider to create a constructor for square, that receives the rectangle and is able of constructing itself from it.
0
evilrixSenior Software Engineer (Avast)Commented:
>> square is derived from rectangle
Not a good class design since a square doesn't really have an isa relationship with a rectangle. It has an implemented_in_terms_of relationship!

>> you can alway cast
>> square *squP = (square *)&rec;
Um, using a C cast in C++ is always dangerous and should never be done!

Downcasting (going from sub class to super class) implies bad design and shouldn't really be necessary if you class hierachy is correct; however, the safe(est) was to do it is with the dynamic_cast operator

square *squP = dynamic_cast<square *>(&rec;);
if(squP) {
   // cast was ok
}

http://www.cplusplus.com/doc/tutorial/typecasting.html
0
Cloud Class® Course: Microsoft Exchange Server

The MCTS: Microsoft Exchange Server 2010 certification validates your skills in supporting the maintenance and administration of the Exchange servers in an enterprise environment. Learn everything you need to know with this course.

evilrixSenior Software Engineer (Avast)Commented:
Note, for dynamic_cast to work the class hierarchy MUST be polymorphic (ie, there needs to be at least one virtual function) and RTTI (Run Time Type Information) must be enabled.
0
lucky_jamesCommented:
Let me reiterate your problem:
how to get derived class pointer out of base class pointer. Right?

you stated one statement:
Derived *ptr = &base;

You can see 2 scenarios in such cases:
1. base class pointer pointer to a base class object. i.e. base* ptr = new base();
You wont be getting a derived class object out of a base class object. But vice versa is always possible. So, in this scenario, it is not possible to get derived class pointer work for you.

2. base class pointer pointer to a derived class object. i.e. base* ptr = new derived();
You can get a derived class pointer work for you in such a case. this is becoz the actual object is that of a derived class.


Now how to cover both of these scenarios??



For that use
Derived* ptr = dynamic_cast<Derived*>(basePtr);

This will return NULL when not cast is not possible. else it will do the job for you.

More on RTTI; check out:
http://asingh.net/technical/rtti.html

Hope it helps.

James

0
Infinity08Commented:
>> but you cannot
>> 
>> square *squP = &rec;

Or, in other words, the question is : why do you need to do this ?
0
itsmeandnobodyelseCommented:
>>>> Overloading the assignment operator for a pointer, is it possible?
You only can overload operator= for a class and not for a pointer.

class Rectangle
{
     int l, t, r, b;
public:
     friend Rectangle& operator=(Rectangle*& pr1, const Rectangle*& pr2)
     {
         *pr1 = *pr2;
         return *pr1;
     }
};

The above wouldn't compile:   'operator=' must be a non-static member.

But you could assign a pointer to a Rectangle object:

class Rectangle
{
     int l, t, r, b;
public:
     Rectangle() : l(0), t(0), r(0), b(0) {}
     Rectangle(int left, int top, int right, int bottom)
      : l(left), t(top), r(right), b(bottom) {}

     Rectangle& operator=(const Rectangle*& pr2)
     {
         *this = *pr2;
         return *this;
     }
};

int main()
{
    Rectangle rec1;
    Rectangle* prec2 = new Rectangle(1, 2, 3, 4);
    rec1 = prec2;    // ok


You also could 'misuse' the operator= overload to assign a baseclass pointer:

class Rectangle : public Shape
{
     int l, t, r, b;
public:
     Rectangle() : l(0), t(0), r(0), b(0) {}
     Rectangle(int left, int top, int right, int bottom)
      : l(left), t(top), r(right), b(bottom) {}

     Rectangle& operator=(const Shape*& pr2)
     {
         l = t = r = b = 0;  // ????
         return *this;
     }
};

But obviously that is nonsense as the 'Shape' baseclass couldn't provide the members needed for the derived object.


       






0
Kent OlsenData Warehouse Architect / DBACommented:
Hi justinvoels,


I think that itsmeandnobodyelse is pretty close to the "best" answer.  Instead of defining Square as a wrapper class to Rectangle, define any Square related methods/objects in Rectangle.  The methods would test that the class object is a square and throw (or return) an error if not.  That's a lot cleaner than trying to "miscast" a pointer.

class Rectangle
{
  private:
    int height, width;
...
 public:
    int isSquare (){return height == width;};
//  Other "Square" methods"
};

Note that that implementation works with a Rectangle class managing all shaped objects, or with both Square (as wrapper) and Rectangle classes.  


Good Luck,
Kent
0
evilrixSenior Software Engineer (Avast)Commented:
>> trying to "miscast" a pointer.
The use of dynamic_cast isn't mis-casting, although it is probably unnecessary.

Two things: -
   (a) a square is not a rectangle so this class hierarchy is, at best,  wrong (it should have an 'is_implemented_in_terms_of' and not an 'is_a' relationship -- or private vs. public inheritance)
   (b) a downcast nearly always means the class hierarchy is wrong (e.g. the interfaces and/or hierarchy have not been through through properly) and therefore a re-think is probably in order.

There is no real right way to do since a downcast is nearly always a compromise of poor design.

-Rx.
0
oleberCommented:
In geometry, a rectangle is defined as a quadrilateral where all four of its angles are right angles. So a square is a rectangle, This is not untouchable.

Before continuing with this discution, we should wait for one clarification of the question.
0
Kent OlsenData Warehouse Architect / DBACommented:

Hi Rx,

Didn't mean to imply that the dynamic_cast was a mis-cast.  But recasting an object its base (or wrapper) class certainly can be dead wrong.  The programmer is injecting a complexity and danger that should be avoided.  Calling the wrong class method results in an memory overrun, which is contrary to one of the safeguards of the C++ strong type casting.  Better (in my opinion) to treat the Square as a special case Rectangle.

(a) -- A square is a special case rectangle where height == width.  (It's also a special case parallelogram where the interior anges are all 90 degrees.)


Kent
0
evilrixSenior Software Engineer (Avast)Commented:
>> So a square is a rectangle, This is not untouchable
This is not geometry and you over-simplify how classes should be modeled. A square is a special kind of rectangle it is not; however, a rectangle (the word special being the key thing here) therefore it does not have an is_a relationship but; rather, it has an implemented_in_terms_of relationship. A rectangle has properties and implementation that do not belong to a square. Consider, a rectangle has two functions, set_w() and set_h(), which allow both width and height to be set separately. How does this apply to a square? It doesn't since you must always ensure width and height are set atomically. Being able to set them separately has no meaning in a class designed to model a square. This being the case a square cannot possible be a rectangle; otherwise, these functions would also be appropriate.

>> But recasting an object its base (or wrapper) class certainly can be dead wrong.
I completely agree

>> The programmer is injecting a complexity and danger that should be avoided
And, if the design is thought out, can

>> Square as a special case Rectangle
Special, but not is_a (see above)

-Rx.
0
Infinity08Commented:
Just supporting what evilrix says about squares not being rectangles :

        http://www.parashift.com/c++-faq-lite/proper-inheritance.html#faq-21.6


Before continuing, I'd like this question answered by justinvoels :

        Why do you need to cast a rectangle pointer to a square pointer ?

The answer to that question will most likely reveal the design flaw.
0
evilrixSenior Software Engineer (Avast)Commented:
>> Why do you need to cast a rectangle pointer to a square pointer ?
Overlooking the fact it's a downcast (and as discussed these are a bad idea normally), you could end up with a square with different length sides... it makes no sense :)

Below is how you might do this safely(ish).

Note, it's quick and dirty code so I don't claim it to be defect free :)

-Rx.
#include <stdexcept>
 
class Rectangle
{
public:
	Rectangle(unsigned int w, unsigned int h): w_(w), h_(h){}
 
	void set_w(unsigned int w) { w_ = w; }
	void set_h(unsigned int h) { h_ = h; }
 
	unsigned int get_w() const { return w_; }
	unsigned int get_h() const { return h_; }
 
private:
	unsigned int w_;
	unsigned int h_;
};
 
class Square : private Rectangle // This is NOT is_a; rather it is implemented_in_terms_of
{
public:
	Square(unsigned int s): Rectangle(s, s){}
 
	Square(Rectangle const & r): Rectangle(r) // Assignment operator left out for brevity
	{
		if(r.get_h() != r.get_w())
		{
			throw std::runtime_error("Rectabgle is not a square");
		}
	}
 
	void set_s(unsigned int s)
	{
		this->set_w(s);
		this->set_h(s);
	}
 
	unsigned int get_s() const { return this->get_w(); } // Return w or h -- it doesn't matter!
};
 
 
int main () {
	Rectangle r1(1,2);
	Square s1(2);
 
	Rectangle r2(s1.get_s(), s1.get_s()); // From square
	Square s2(r1); // From rectangle -- unsafe: this might throw
 
	Rectangle r3(r2); // Safe
	Square s3(s2); // Safe
 
	return 0;
}

Open in new window

0
justinvoelsAuthor Commented:
Thanks, guys. I know that my example in nonsensical, shapes are just the typical example people will use when describing something related to classes. I figured it would be a very bad idea (I know it is a very bad idea from an assembly and architecture standpoint). Often times people can forget that the only reason you can't do some things is because the compiler (right in doing so, typically) says no.

Next time I will be sure to include that my question is hypothetical and the example isn't actually useful code.

I had a discussion about this topic and it came up, making me curious,  just expanding the knowledge of the language, even if it isn't particularly useful and will cause trouble (if not explicitly managed and tracked).
0
Infinity08Commented:
If you would have answered my question, we could have given you some more specific answers ...
0
Kent OlsenData Warehouse Architect / DBACommented:

>> A rectangle has properties and implementation that do not belong to a square. Consider, a rectangle has two functions, set_w() and set_h(), which allow both width and height to be set separately

That can mostly be handled at instantiation.

Rectangle::Rectangle (int Size) { height = Size; width = Size; Square = true;};
Rectangle::Rectangle (int h, int w) { height = h; width = w; Square = (h == w)};



I'm enjoying this discussion.  :)

Kent
0
evilrixSenior Software Engineer (Avast)Commented:
>> That can mostly be handled at instantiation.
The point is, the model is wrong for the reasons I've already explained.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
C++

From novice to tech pro — start learning today.