Assignment Operator In Case of Inheritance

C

Clifton M. Bean

First, I defined three classes (listed below):

===========
// 1st class
===========
class PointCl
{
public:
PointCl & operator= (const PointCl & rgh ); //define as usual
assingment operator
private:
double _x;
}

===========
// 2nd class
===========
class Ball :: public PointCl
{
public:
Ball & operator= (const Ball & );
private:
double _r;
}

Ball & Ball::eek:perator( const Ball & rgh )
{
if( this != & rgh )
{
PointCl::eek:perator= rgh;
// static_cast<PointCl & > (*this) = rgh; I tried to this as well
_r = rgh._r;
}
}

===============
3rd class
===============
class ChainCl
{
private:
............
public:
std::vector<Ball> _vBall;
PointCl _cntrCrav;
}
===========

Interestingly, this code runs okay in Visual Studio; however, I get the
following error when I try to link the same files on a Solaris machine:

rm -f driver PointCl.o Distance.o Ball.o ChainCl.o driver.o
make[1]: Entering directory `/home/cs/k/kathym/Bioinformatics/myPart'
g++ -Wall -c -gstabs driver.cxx
g++ -Wall -c -gstabs ChainCl.cxx
g++ -Wall -c -gstabs Ball.cxx
g++ -Wall -c -gstabs PointCl.cxx
g++ -Wall -c -gstabs Distance.cxx
g++ -Wall -gstabs driver.o ChainCl.o -lm -o driver
Undefined first referenced
symbol in file
Ball::eek:perator=(Ball const&) ChainCl.o
operator<<(std::basic_ostream<char, std::char_traits<char> >&, PointCl
const&)dr
iver.o
ld: fatal: Symbol referencing errors. No output written to driver
collect2: ld returned 1 exit status
make[1]: *** [driver] Error 1
make[1]: `PointCl.o' is up to date.
make[1]: `Distance.o' is up to date.
make[1]: `Ball.o' is up to date.
make[1]: `ChainCl.o' is up to date.
make[1]: `driver.o' is up to date.
make[1]: Leaving directory `/home/cs/k/kathym/Bioinformatics/myPart'
make: *** [all] Error 2

Please help me figure this out or determine a way to determine why all is
okay within Visual Studio and not within a Solaris UNIX environment.

Thank you in advance.
Kathryn Bean
 
J

Josephine Schafer

Clifton M. Bean said:
First, I defined three classes (listed below):

Couple of points to note.
First, please copy-paste the actual code you are working on. There are many
trivial mistakes in the code below.
This saves everyone's time..you don't need to type the full code again as
well.
===========
// 1st class
===========
class PointCl
{
public:
PointCl & operator= (const PointCl & rgh ); //define as usual
assingment operator
private:
double _x;

Not a good idea to name variable with leading underscores.
Better to rename it as x_.
;
Missing semicolon
===========
// 2nd class
===========
class Ball :: public PointCl

class Ball : public PointCl
{
public:
Ball & operator= (const Ball & );
private:
double _r;

Rename the varaible here too.
;
Missing semicolon.
Ball & Ball::eek:perator( const Ball & rgh )

Ball & Ball::eek:perator=( const Ball & rgh )
{
if( this != & rgh )
{
PointCl::eek:perator= rgh;
PointCl::eek:perator=(rgh);


// static_cast<PointCl & > (*this) = rgh; I tried to this as well
_r = rgh._r;
}
You need to return the LHS operand here.
return *this
}

===============
3rd class
===============
class ChainCl
{
private:
...........
public:
std::vector<Ball> _vBall;
PointCl _cntrCrav;
}
===========


Also, you need to #include<vector> because you use vector template class in
your code .
Also provide an implementation for base class assignment operator..else you
are bound to get linker errors.

HTH,
J.Schafer

(Remove no_spam_ to contact by mail)
 
K

Kevin Goodsell

Ron said:
Nothing wrong with it here.

IMHO, the best practice is to get in the habit of *not* using
identifiers that begin with an underscore. That way you avoid any
problems without even thinking about it.

-Kevin
 
J

Josephine Schafer

Ron Natalie said:
Nothing wrong with it here.
It's entirely a matter of style. I prefer this style like Kevin does.

ok..let me quote Herb Sutter here -

<Quote>
"Try to avoid names with leading underscores. Yes, I've habitually used
them, and yes, popular books like "Design Patterns" (Gamma et al) do use
it... but the standard reserves some leading-underscore identifiers for the
implementation and the rules are hard enough to remember (for you and for
compiler writers!) that you might as well avoid this in new code. (Since I'm
no longer allowed to use leading underscores as my "member variable" tag,
I'll now use trailing underscores!)".
</Quote>

in his article http://www.gotw.ca/gotw/004.htm .
 
C

Clifton M. Bean

Gianni Mariani said:
I suggest you post compilable code.
I have listed the compilable code below, as requested.

Again, please let me explain the problem. I wrote assignment operator for a
derived class (Ball class inherited from PointCl class) according to the
recommendation from the book, "Effective C++" by Scott Meyers. The ChainCl
object has a vector from STL which is populated by Ball objects. When I
compile the code under Visual Studio, no problems; when I take the same
code and compile it under UNIX (Solaris), I get the following error:

rm -f driver PointCl.o Distance.o Ball.o ChainCl.o driver.o
make[1]: Entering directory `/home/cs/k/kathym/Bioinformatics/myPart'
g++ -Wall -c -gstabs driver.cxx
g++ -Wall -c -gstabs ChainCl.cxx
g++ -Wall -c -gstabs Ball.cxx
g++ -Wall -c -gstabs PointCl.cxx
g++ -Wall -c -gstabs Distance.cxx
g++ -Wall -gstabs driver.o ChainCl.o -lm -o driver
Undefined first referenced
symbol in file
Ball::eek:perator=(Ball const&) ChainCl.o
operator<<(std::basic_ostream<char, std::char_traits<char> >&, PointCl
const&)dr
iver.o
ld: fatal: Symbol referencing errors. No output written to driver
collect2: ld returned 1 exit status
make[1]: *** [driver] Error 1
make[1]: `PointCl.o' is up to date.
make[1]: `Distance.o' is up to date.
make[1]: `Ball.o' is up to date.
make[1]: `ChainCl.o' is up to date.
make[1]: `driver.o' is up to date.
make[1]: Leaving directory `/home/cs/k/kathym/Bioinformatics/myPart'
make: *** [all] Error 2

Please help me figure this out or determine a way to determine why all is
okay within Visual Studio and not within a Solaris UNIX environment. I have
more experience using Visual C++ than using UNIX g++ compiler.

Thank you in advance.
Kathryn Bean

==========================================
PointCl.h
==========================================
#ifndef POINTCL_H
#define POINTCL_H

#include <iostream>
class PointCl
{
friend std::eek:stream & operator<< (std::eek:stream & , const PointCl & );
public:
PointCl( )
: x_(0.0), y_(0.0), z_(0.0)
{ }
PointCl( double x, double y, double z )
: x_(x), y_(y), z_(z)
{ }
PointCl( const PointCl & pnt )
: x_( pnt.x_), y_( pnt.y_ ), z_( pnt.z_ )
{ }
PointCl & operator= (const PointCl &rgh );
virtual ~PointCl()
{ }
void setX (double x) {x_ = x;}
void setY (double y) {y_ = y;}
void setZ (double z) {z_ = z;}
double getX( ) const {return x_; }
double getY( ) const {return y_; }
double getZ( ) const {return z_; }

void movePoint( double distX, double distY, double distZ )
{
x_ =+ distX;
y_ =+ distY;
z_ =+ distZ;
}
private:
double x_;
double y_;
double z_;
};
#endif
====================================
PointCl.cxx
====================================
#include <assert.h>
#include <iostream>
#include "PointCl.h"

PointCl & PointCl::eek:perator= (const PointCl &rgh )
{
if( &rgh != this )
{
x_ = rgh.x_;
y_ = rgh.y_;
z_ = rgh.z_;
}
return *this;
}
/********************************************************/
std::eek:stream & operator<< (std::eek:stream & out, const PointCl & p)
{
out << p.x_ << "," << p.y_ << "," << p.z_ << std::endl;
return out;
}
===================================================
Ball.h
===================================================
#ifndef BALL_H
#define BALL_H

#include <iostream>
#include "PointCl.h"

class Ball : public PointCl
{
friend std::eek:stream & operator<< (std::eek:stream & out, const Ball & );
public:
Ball( )
: PointCl(), r_(0.0)
{ }
Ball( double x, double y, double z, double r )
: PointCl( x, y, z), r_(r)
{ }
Ball( const Ball & ball )
: PointCl( ball ), r_(ball.r_ )
{ }
virtual ~Ball()
{ }
Ball & operator= ( const Ball & ball );
double getR() const { return r_; }
bool operator> (const Ball& rgh ) const { return r_ > rgh.r_; }
bool operator< (const Ball& rgh ) const { return r_ < rgh.r_; }
bool operator>= (const Ball& rgh ) const { return r_ >= rgh.r_; }
bool operator<= (const Ball& rgh ) const { return r_ <= rgh.r_; }
private:
double r_;
};
#endif
==================================================
Ball.cpp
=================================================
#include <iostream>
#include "Ball.h"
//
// Here is the assignment operator
//
Ball & Ball::eek:perator= ( const Ball & rgh )
{
if( this != &rgh )
{
static_cast < PointCl& > (*this) = rgh;
r_ = rgh.r_;
}
return *this;
}
/*****************************************************************/
std::eek:stream & operator<< (std::eek:stream & out, const Ball & b)
{
out << "[ " << static_cast< PointCl >( b ) << b.r_ << "]" <<
std::endl;
return out;
}
===========================================================
ChainCl.h
===========================================================
#ifndef CHAINCL_H
#define CHAINCL_H

#include <vector>
#include "PointCl.h"
#include "Ball.h"

class ChainCl
{
public:
typedef std::vector<Ball> v_ball;
typedef std::vector<Ball> ::iterator v_ball_itr;
typedef std::vector<Ball> ::const_iterator v_ball_const_itr;
ChainCl()
: cntrGrav_(0.0, 0.0, 0.0)
{ }
void populateChain( );
void calculateCentGrav( );
void printChain( ) const;
const PointCl & getCntrGravity( ) { return cntrGrav_; }
const v_ball & getVectorBalls( ) {return vBall_; }
private:
v_ball vBall_;
PointCl cntrGrav_;
};
#endif
====================================================
ChainCl.cxx
====================================================
#include <stdlib.h>
#include <iostream>
#include <assert.h>
#include "ChainCl.h"
#include "Ball.h"

void ChainCl::populateChain( )
{
for(int i=1; i <= 5; i++ )
{
double x = (double)( rand() % 200 ) / 10.0;
double y = (double)( rand() % 200 ) / 10.0;
double z = (double)( rand() % 200 ) / 10.0;
double r = (double)( 10 + rand() % 200 ) / 10.0;

Ball ball( x ,y, z, r);
vBall_.push_back( ball );
}
}
/************************************************************/
void ChainCl::printChain( ) const
{
v_ball_const_itr p;
for( p = vBall_.begin(); p != vBall_.end(); ++p )
{
std::cout << p->getR();
}
std::cout << std::endl;
}
/**************************************************************/
void ChainCl::calculateCentGrav( )
{
int size = vBall_.size();
assert( size > 0 );
double sumX = 0.0;
double sumY = 0.0;
double sumZ = 0.0;

v_ball_const_itr p;
for( p = vBall_.begin(); p != vBall_.end(); ++p )
{
sumX = sumX + ( p->getX() );
sumY = sumY + ( p->getY() );
sumZ = sumZ + ( p->getZ() );
}
cntrGrav_.setX( sumX/size );
cntrGrav_.setY( sumY/size );
cntrGrav_.setZ( sumZ/size );

return;
}
==================================================
driver.h
==================================================
#include <iostream>
#include "ChainCl.h"
#include "PointCl.h"

int main()
{
ChainCl chain;
chain.populateChain();
chain.printChain();
chain.calculateCentGrav()
std::cout << "Center Gravity: " << chain.getCntrGravity() <<
std::endl;
return 0;
}
 
F

Frank Schmitt

Clifton M. Bean said:
Gianni Mariani said:
I suggest you post compilable code.
I have listed the compilable code below, as requested.

Again, please let me explain the problem. I wrote assignment operator for a
derived class (Ball class inherited from PointCl class) according to the
recommendation from the book, "Effective C++" by Scott Meyers. The ChainCl
object has a vector from STL which is populated by Ball objects. When I
compile the code under Visual Studio, no problems; when I take the same
code and compile it under UNIX (Solaris), I get the following error:

rm -f driver PointCl.o Distance.o Ball.o ChainCl.o driver.o
make[1]: Entering directory `/home/cs/k/kathym/Bioinformatics/myPart'
g++ -Wall -c -gstabs driver.cxx
g++ -Wall -c -gstabs ChainCl.cxx
g++ -Wall -c -gstabs Ball.cxx
g++ -Wall -c -gstabs PointCl.cxx
g++ -Wall -c -gstabs Distance.cxx

You forgot to poste Distance.cxx - but you apparently don't need it,
anyway :)
g++ -Wall -gstabs driver.o ChainCl.o -lm -o driver
Undefined first referenced
symbol in file
Ball::eek:perator=(Ball const&) ChainCl.o
operator<<(std::basic_ostream<char, std::char_traits<char> >&, PointCl
const&)dr
iver.o

You forgot to link Ball.o and PointCl.o; the following command works for me
(gcc 3.3.1 on RH Linux):
g++ -Wall -gstabs Ball.o ChainCl.o PointCl.o driver.o -lm -o driver

==================================================
driver.h
==================================================
#include <iostream>
#include "ChainCl.h"
#include "PointCl.h"

int main()
{
ChainCl chain;
chain.populateChain();
chain.printChain();
chain.calculateCentGrav()

Missing semicolon in this line.

HTH & kind regards
frank
 
J

jeffc

Josephine Schafer said:
ok..let me quote Herb Sutter here -

<Quote>
"Try to avoid names with leading underscores. Yes, I've habitually used
them, and yes, popular books like "Design Patterns" (Gamma et al) do use
it... but the standard reserves some leading-underscore identifiers for the
implementation and the rules are hard enough to remember (for you and for
compiler writers!) that you might as well avoid this in new code. (Since I'm
no longer allowed to use leading underscores as my "member variable" tag,
I'll now use trailing underscores!)".
</Quote>

Interesting. On the surface, that's just more flamebait for the anti-Sutter
brigade. But then he himself mentions one of the holy scripts. Quite a
dilemma........
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,142
Messages
2,570,819
Members
47,367
Latest member
mahdiharooniir

Latest Threads

Top