By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
435,619 Members | 2,309 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 435,619 IT Pros & Developers. It's quick & easy.

using assignment operator

P: n/a
Hello Experts!

Assume I have a class called SphereClass as the base class and a class
called BallClass that is derived from the SphereClass. The copy constructor
initialize the left hand object in this case object b2 below. It also
initialize subobject from class SphereClass.

The BallClass copy constructor looks like this.
BallClass::BallClass(const BallClass& bc) : SphereClass(bc)

int main()
{
BallClass b1("ball");

BallClass b2(b1);
return 0;
}

Now to my question when you use assignment for example
b2 = b1
how do you initialize the subobject part from class SphereClass. When I used
the copy constructor I initialized the subobject part by using this
statement SphereClass(bc)

Many thanks!

//Tony
Aug 9 '05 #1
Share this Question
Share on Google+
14 Replies


P: n/a
Tony Johansson wrote:
Assume I have a class called SphereClass as the base class and a class
called BallClass that is derived from the SphereClass. The copy constructor
initialize the left hand object in this case object b2 below. It also
initialize subobject from class SphereClass.

The BallClass copy constructor looks like this.
BallClass::BallClass(const BallClass& bc) : SphereClass(bc)

int main()
{
BallClass b1("ball");

BallClass b2(b1);
return 0;
}

Now to my question when you use assignment for example
b2 = b1
how do you initialize the subobject part from class SphereClass.
When you use assignment, nothing is _initialised_. Everything is
_assigned_. What example of the copy assignment operator does your
favourite C++ book give? What do you not understand in that example?

BTW, what do you not like about the compiler-generated copy assignment
operator? Does it not work for you for some reason?
When I used
the copy constructor I initialized the subobject part by using this
statement SphereClass(bc)


We noticed. Initialiser lists are a feature of _constructors_only_.

V
Aug 9 '05 #2

P: n/a
Tony, Does your base class SphereClass have a copy constructor? If so,
then your memberwise initialization statement SphereClass(bc) is okay.
Otherwise if your base class does not have a copy constructor, default
memberwise initialization is recursively applied to the base class.

Aug 9 '05 #3

P: n/a
Victor, Compiler-generated copy assignment operators are not always the
best choice. Tony has not provided us with a full description of his
class. If his base class contains any members which are pointers to
dynamically allocated memory, I would not use the compiler-generated
copy assignment operators. Instead, I would write my own as Tony
suggests.

Aug 9 '05 #4

P: n/a
Frank Chang wrote:
Victor, Compiler-generated copy assignment operators are not always the
best choice. Tony has not provided us with a full description of his
class. If his base class contains any members which are pointers to
dynamically allocated memory, I would not use the compiler-generated
copy assignment operators. Instead, I would write my own as Tony
suggests.


Frank, my question wasn't to suggest that compiler-generated assignment
operators are the best choice always. My question was to make Tony think
about it and give _his_ answer. Thanks for chiming in, though.

V
Aug 9 '05 #5

P: n/a
Tony Johansson wrote:

Hello Experts!
Now to my question when you use assignment for example
b2 = b1
how do you initialize the subobject part from class SphereClass.


By calling the assignment operator for the base class.
In your case, it could be done eg by:

BallClass& BallClass::operator=( const BallClass& rhs )
{
SphereClass::operator=( rhs );

// do whatever is necc. additionally for a BallClass object

return *this;
}

As others have pointed out: You need to work on your terminologie.
Especially the distinction between assignment and initialization.
And what you called 'the statement' is known as initializer list

--
Karl Heinz Buchegger
kb******@gascad.at
Aug 9 '05 #6

P: n/a
Frank Chang wrote:

Victor, Compiler-generated copy assignment operators are not always the
best choice.
If they do the right thing, then yes they are.
Tony has not provided us with a full description of his
class. If his base class contains any members which are pointers to
dynamically allocated memory, I would not use the compiler-generated
copy assignment operators.


:-)
Especially in this case I would let the compiler do it.
(Note: You wrote: if the *base* class ...
In the derived class I don't care what the base class does. The compiler
generated op= of the *derived* class, does the right thing: it calls the
op= of the base class and that's all there needs to be such that the *base*
class op= gets a chance to get it right.

--
Karl Heinz Buchegger
kb******@gascad.at
Aug 9 '05 #7

P: n/a
Karl Heinz Buchegger writes:

"In the derived class I don't care what the base class does. The
compiler
generated op= of the *derived* class, does the right thing: it calls
the
op= of the base class and that's all there needs to be such that the
*base* class op= gets a chance to get it right. "

Suppose we have the scenario b2 = b1 where b1 and b2 are derived
objects of type BallObject. Suppose the base class of BallObject,
SphereClass has a member variable which is a pointer to an object of
class Foo. If we use the compiler generated assignment operator for
the base class SphereClass, then in most compilers it will make a
bitwise copy of the pointer to an object of Foo. Now, suppose the
virtual destructors for b1 and b2 get called eventually, then you will
be double deleting the Foo pointer member of b1 and b2. Please name a
widely used compiler which avoids this problem.

Aug 9 '05 #8

P: n/a
Frank Chang wrote:
Karl Heinz Buchegger writes:

"In the derived class I don't care what the base class does. The
compiler
generated op= of the *derived* class, does the right thing: it calls
the
op= of the base class and that's all there needs to be such that the
*base* class op= gets a chance to get it right. "

Suppose we have the scenario b2 = b1 where b1 and b2 are derived
objects of type BallObject. Suppose the base class of BallObject,
SphereClass has a member variable which is a pointer to an object of
class Foo. If we use the compiler generated assignment operator for
the base class SphereClass,
I think you don't understand what Karl Heinz is saying: BallObject should
not care whether SphereClass has its assignment operator compiler-created
or user-defined. Now, if SphereClass has some dynamic memory management
to accomplish, BallObject doesn't have to, or, more often, shouldn't, care
about that when using SphereClass' operator=.
then in most compilers it will make a
bitwise copy of the pointer to an object of Foo. Now, suppose the
virtual destructors for b1 and b2 get called eventually, then you will
be double deleting the Foo pointer member of b1 and b2. Please name a
widely used compiler which avoids this problem.


Please reread Karl's post.

V
Aug 9 '05 #9

P: n/a
I read Karl's post before I posted and I understand what he is saying.
However, in proper C++ design, all C++ classes, including base
classes, must adhere to a contract and implement the canonical
operators such as copy constructor, assignment operator, destructor
correctly. Otherwise , all subsequently derived classes from these base
classes, no matter how cleverly designed or implemented, will exhibit
erratic run time behavior. The ARM by Bjarne Strousoup discusses this
issue in detail.

Aug 9 '05 #10

P: n/a
Frank Chang wrote:
I read Karl's post before I posted and I understand what he is saying.
However, in proper C++ design, all C++ classes, including base
classes, must adhere to a contract and implement the canonical
operators such as copy constructor, assignment operator, destructor
correctly.
What does "correctly" mean? I inherit from a class. I have no idea how
it maintains its members, whether it has any dynamic memory management or
not. Why should I care about it _at_all_? And don't refer me to ARM,
give your explanation.
Otherwise , all subsequently derived classes from these base
classes, no matter how cleverly designed or implemented, will exhibit
erratic run time behavior. The ARM by Bjarne Strousoup discusses this
issue in detail.


Which portion of ARM discusses that derived classes should know how base
classes maintain their dynamic memory? The chapter/verse, please.

V
Aug 9 '05 #11

P: n/a
Victor, I will get back to you ASAP. Since this bulletin board is
conducted under the rules of gentle(wo)men. I will consider it an act
of cowardice if I don't do my best to answer your question. Thank you.

Aug 9 '05 #12

P: n/a
Frank Chang wrote:

Karl Heinz Buchegger writes:

"In the derived class I don't care what the base class does. The
compiler
generated op= of the *derived* class, does the right thing: it calls
the
op= of the base class and that's all there needs to be such that the
*base* class op= gets a chance to get it right. "

Suppose we have the scenario b2 = b1 where b1 and b2 are derived
objects of type BallObject. Suppose the base class of BallObject,
SphereClass has a member variable which is a pointer to an object of
class Foo. If we use the compiler generated assignment operator for
the base class SphereClass,
Neither you nor I claimed to let the compiler generate the op= for
SphereClass. We were talking about BallClass. You might want to reread
what you wrote and what I wrote (and also note the smiley).
then in most compilers it will make a
bitwise copy of the pointer to an object of Foo. Now, suppose the
virtual destructors for b1 and b2 get called eventually, then you will
be double deleting the Foo pointer member of b1 and b2. Please name a
widely used compiler which avoids this problem.

Question:
In the following example, does the compiler genberated BallClass::op=
do the right thing or not?
Answer: Yes it does

#include<stdio.h>

class SphereClass
{
public:
SphereClass()
{ m_Dynamic = new int [100];
for( int i = 0; i < 100; ++i )
m_Dynamic[i] = i;
}

~SphereClass()
{
delete [] m_Dynamic;
}

SphereClass& operator=( const SphereClass& rhs )
{
int* tmp = new int [100];
for( int i = 0; i < 100; ++i )
tmp[i] = rhs.m_Dynamic[i];
delete [] m_Dynamic;
m_Dynamic = tmp;
return *this;
}

private:
int* m_Dynamic;
};

class BallClass : public SphereClass
{
public:
BallClass( int n )
{
m_Number = n;
}

private:
int m_Number;
};

int main()
{
BallClass b1( 5 ), b2( 7 );

b1 = b2;
return 0;
}

--
Karl Heinz Buchegger
kb******@gascad.at
Aug 10 '05 #13

P: n/a
Victor, With regard to your first question,
"What does "correctly" mean? I inherit from a class. I have no idea
how
it maintains its members, whether it has any dynamic memory management
or
not. Why should I care about it _at_all_?"

In the classic tome , "Advanced C++ Programming Styles and Idioms" ,
the renowned expert James O. Coplien writes "Programmers are
responsible for preserving the intuitive meaning of assignment in the
code they write; there is nothing in the language or compiler that will
force you to do what makes sense! To read why bitwise copy does not
work--and why even member-by-member copy does not always without some
help - see Appendix D,,,,,," I think James O. Coplien elegantly answers
your questions. 1) What does correctly mean? 2) Why care about it at
all? Please email me at fr***********@hotmail.com if you want a copy of
Appendix D.

Finally , about the ARM ( 1st edition), you have to read between the
lines but in Chapter 12 , Section 8 Margaret Ellis and Bjarne
Stroustrup acknowledge that compiler generated copy constructors and
assignment operators in all classes , no matter whether they are base
or derived classes, should not always be used, "In practice, a good
compiler can generate bitwise copies for *most* class objects since
they have the bitwise copy semantics". Also , in the preface, Margeret
Ellis and Bjarne Stroustrup state "This C++ reference manual alone
provides a complete definition of C++, but the terse reference style
leaves many reasonable questions unanswered." So if you read the entire
manual in its entirety and implement and test copy constructors and
assignment operators for many base and derived classes following the
C++ language constructs described in the ARM, you will see why derived
classes should know how their base classes maintain their dynamic
memory.
For example, suppose you buy a 3rd party C++ library like
RogueWave. RogueWave provides you with the header files ( and source
code if you have the bucks) which show which private and protected
member variables
of their base classes use dynamically allocated library. Now, suppose
you don't care how their base classes implement their copy constructor,
default constructor, assignment operator and destructor and you
implement a class hierarchy based on RogueWave's base classes. Then,
one day, one of your customer calls up and tells you that your software
generates GP faults or leaks memory. After you look at your derived
classes and verify that the bug is not in the implenatation of your
derived classes, you have to ask RogueWave if the problem is in their
base class implementation. Since you paid RogueWave a lot of money to
buy their class framework, you have to ship RogueWave a whole bunch of
test code which help them determine whether you are using their base
classes correctly or whether they have to issue you a patch fix. I have
done this several times and I sure you have had to do the same thing
with the 3rd party libraries you have purchased. Regards , Frank

Aug 11 '05 #14

P: n/a
Frank Chang wrote:
Victor, With regard to your first question,
"What does "correctly" mean? I inherit from a class. I have no idea
how
it maintains its members, whether it has any dynamic memory management
or
not. Why should I care about it _at_all_?"

In the classic tome , "Advanced C++ Programming Styles and Idioms" ,
the renowned expert James O. Coplien writes "Programmers are
responsible for preserving the intuitive meaning of assignment in the
code they write; there is nothing in the language or compiler that will
force you to do what makes sense! To read why bitwise copy does not
work--and why even member-by-member copy does not always without some
help - see Appendix D,,,,,," I think James O. Coplien elegantly answers
your questions. 1) What does correctly mean? 2) Why care about it at
all? Please email me at fr***********@hotmail.com if you want a copy of
Appendix D.
I am very sorry you've misunderstood James Coplien's text. In the last
part of Appendix D he writes "This adaptation works well when in
situations where everything is a class object." A base class subobject
_is_ a class object. Relying on its operator= to do the derived class'
assignment is what we _should_ do (and what James Coplien says is just
what doctor ordered). How the base class object does its own assignment
is up to the implementor of the _base_class_, and should not be a concern
of the implementor of the _derived_ class.

I am not sure how to explain it to you better. You apparently got stuck
in the notion that dynamic memory, pointers, change _everything_. They
only dictate certain precautions in implementing the classes where they
are _the_members_. If a base class has members related to dynamic memory,
the *derived* class shouldn't have to worry about them; "members of my
members are not my members". You can quote _me_ on that. I am not as
renowned as James Coplien, but some do consider me an expert.
Finally , about the ARM ( 1st edition), you have to read between the
lines but in Chapter 12 , Section 8 Margaret Ellis and Bjarne
Stroustrup acknowledge that compiler generated copy constructors and
assignment operators in all classes , no matter whether they are base
or derived classes, should not always be used, "In practice, a good
compiler can generate bitwise copies for *most* class objects since
they have the bitwise copy semantics".
This isn't true and hasn't been true for a very long time. Bitwise
copying has gone in favour of _MEMBER-WISE_ copying ages ago. That's the
correct semantics. Of course bitwise copying is wrong. There is no doubt
about that. Quoting ARM about bitwise copying trying to prove that
member-wise copying shouldn't be relied upon is _bogus_.

As much as the ARM is a great text, it's more than ten years old. Many
things did change since it was conceived. You need to stop living in the
past and get a critical look at the book and what it teaches.
Also , in the preface, Margeret
Ellis and Bjarne Stroustrup state "This C++ reference manual alone
provides a complete definition of C++, but the terse reference style
leaves many reasonable questions unanswered." So if you read the entire
manual in its entirety and implement and test copy constructors and
assignment operators for many base and derived classes following the
C++ language constructs described in the ARM, you will see why derived
classes should know how their base classes maintain their dynamic
memory.
I've read the ARM several times and have NOT found the place in it where
the esteemed authors suggest that derived classes should meddle in the
business of their base classes. YOU failed to show me such place as well,
supplying only some vague "if you read" "you will see". I don't see
it, and that's why I appeal to your [allegedly superior] ability to show
me. Care to try again?
For example, suppose you buy a 3rd party C++ library like
RogueWave. RogueWave provides you with the header files ( and source
code if you have the bucks) which show which private and protected
member variables
of their base classes use dynamically allocated library. Now, suppose
you don't care how their base classes implement their copy constructor,
default constructor, assignment operator and destructor and you
implement a class hierarchy based on RogueWave's base classes. Then,
one day, one of your customer calls up and tells you that your software
generates GP faults or leaks memory. After you look at your derived
classes and verify that the bug is not in the implenatation of your
derived classes, you have to ask RogueWave if the problem is in their
base class implementation. Since you paid RogueWave a lot of money to
buy their class framework, you have to ship RogueWave a whole bunch of
test code which help them determine whether you are using their base
classes correctly or whether they have to issue you a patch fix. I have
done this several times and I sure you have had to do the same thing
with the 3rd party libraries you have purchased. Regards , Frank


This is totally bogus. I am sorry.

What you're suggesting here is that the users of a *faulty* library have
to cover for the [apparently incapable] programmers of that library? No
way. As soon as I find out that the third party library for which I paid
"a lot of money" doesn't live up to simple _sensible_ expectations, there
will be first a request to fix it (for free), and quickly, then, if that
fails, a request to give me my money back, and then, if that fails,
a lawsuit. The makers of high-priced libraries know that. If they are
still in business, that is. If they don't know that, they are most likely
out of business by now. Good riddance.

Get with the program, Frank. If you keep working around the bugs in the
third-party libraries without even trying to help them to fix those bugs
(and until you firmly believe they _are_ bugs and not _normal_behaviour_
for which you try to find justifications in "Advanced C++" or the ARM, you
will not have a reason to try, trust me), you will be stuck using wrong
techniques, advocating those wrong techniques in public forums, and thus
keep others from progress.

V
Aug 11 '05 #15

This discussion thread is closed

Replies have been disabled for this discussion.