C++虚赋值运算符
C++ virtual assignment operator
我正在尝试从派生的 class(点)中的基数 class(形状)调用赋值运算符。我收到未解决的外部链接器错误,我不明白为什么。我将 "virtual" 放在基本赋值运算符的前面,并将基本赋值运算符放在派生的 class 的最后。我哪里做错了?
#ifndef SHAPE_H
#define SHAPE_H
#include <iostream>
using namespace std;
namespace Joe
{
namespace CAD
{
class Shape
{
private:
int m_id;
public:
Shape(); //default constructor
~Shape(); //destructor
Shape(const Shape& s); //copy constructor
virtual Shape& operator = (const Shape& source); //assignment operator
string ToString() const; //returns id as a string
friend ostream& operator << (ostream& os, const Shape& sh); //global function that can access private members
int ID() const;
};
inline int Shape::ID() const //retrieve ID of shape
{
return m_id;
}
}
}
#endif
#ifndef POINT_H
#define POINT_H
#include <iostream>
#include "shape.h"
namespace Joe
{
namespace CAD
{
class Point: public Shape
{
private:
double m_x;
double m_y;
public:
Point(); //default constructor
~Point(); //destructor
Point(const Point& pt); //copy constructor
Point(double newX, double newY) //constructor accepting x and y coordinates
{
m_x = newX;
m_y = newY;
std::cout << "Point(" << m_x <<","<< m_y <<")" << std::endl;
}
Point(double val); //constructor accepting one double
void X(double newXval) {m_x = newXval;} //default inline setter
void Y(double newYval) {m_y = newYval;} //default inline setter
double X() const; //getter pre-inline
double Y() const; //getter pre-inline
std::string ToString() const; //returns a string description
//distance functions
double Distance() const; //calculate the distance to the origin (0,0)
double Distance(const Point& p) const; //calculate the distance between two points
//operator overloading
Point operator - () const; //negate the coordinates
Point operator * (double factor) const; //scale the coordinates
Point operator + (const Point& p) const; //add coordinates
bool operator == (const Point& p) const; //equally compare operator
Point& operator = (const Point& source); //assignment operator
Point& operator *= (double factor); //scale the coordinates and assign
friend std::ostream& operator << (std::ostream& os, const Point& p); //send to ostream (friend)
Shape& operator = (const Shape& source); // call assignment operator of base class
};
inline double Point::X() const //normal inline getter
{
return m_x;
}
inline double Point::Y() const //normal inline getter
{
return m_y;
}
}
}
#endif
Shape& Shape::operator = (const Shape& source) //assignment operator
{
if (this == &source) //avoid self-assignment
return *this;
cout << "shape assignment" << endl;
m_id = source.m_id;
return *this;
}
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
您的问题可能是您在命名空间中定义了 class,但是您在该命名空间之外定义了运算符而没有指定它。因此,编译器无法将定义连接到声明。
Ishamael 指出您没有指定将非点形状分配给点时会发生什么。这对于虚拟赋值运算符是必需的;看到他的回答。但是这个虚拟赋值运算符最终可能会做很多意想不到的事情,比如如果错误的类型被分配给彼此,就会切断部分对象。
您不需要虚拟性来确保在分配 Point 时也调用 Shape 运算符。只需在 Point 运算符中调用 Shape 运算符。使运算符虚拟化实际上会产生相反的效果; Point 运算符将覆盖 Shape 运算符,即使您调用它的实例被称为 Shape。
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
Shape::operator=(source); // also call the base class operator
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
你的问题是,当你调用 operator =
并传递给它一个 Shape
时,你正在调用 Point::operator=(const Shape&)
,你没有定义它,你只定义了 Shape::operator=(const Shape&)
和 Point::operator=(const Point&)
。您需要添加 Point::operator=(const Shape&)
,例如:
Shape& Point::operator = (const Shape& shape) //assign
{
const Point& source = static_cast<Point&>(shape); // or use dynamic_cast here, if you want to be safe
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
我正在尝试从派生的 class(点)中的基数 class(形状)调用赋值运算符。我收到未解决的外部链接器错误,我不明白为什么。我将 "virtual" 放在基本赋值运算符的前面,并将基本赋值运算符放在派生的 class 的最后。我哪里做错了?
#ifndef SHAPE_H
#define SHAPE_H
#include <iostream>
using namespace std;
namespace Joe
{
namespace CAD
{
class Shape
{
private:
int m_id;
public:
Shape(); //default constructor
~Shape(); //destructor
Shape(const Shape& s); //copy constructor
virtual Shape& operator = (const Shape& source); //assignment operator
string ToString() const; //returns id as a string
friend ostream& operator << (ostream& os, const Shape& sh); //global function that can access private members
int ID() const;
};
inline int Shape::ID() const //retrieve ID of shape
{
return m_id;
}
}
}
#endif
#ifndef POINT_H
#define POINT_H
#include <iostream>
#include "shape.h"
namespace Joe
{
namespace CAD
{
class Point: public Shape
{
private:
double m_x;
double m_y;
public:
Point(); //default constructor
~Point(); //destructor
Point(const Point& pt); //copy constructor
Point(double newX, double newY) //constructor accepting x and y coordinates
{
m_x = newX;
m_y = newY;
std::cout << "Point(" << m_x <<","<< m_y <<")" << std::endl;
}
Point(double val); //constructor accepting one double
void X(double newXval) {m_x = newXval;} //default inline setter
void Y(double newYval) {m_y = newYval;} //default inline setter
double X() const; //getter pre-inline
double Y() const; //getter pre-inline
std::string ToString() const; //returns a string description
//distance functions
double Distance() const; //calculate the distance to the origin (0,0)
double Distance(const Point& p) const; //calculate the distance between two points
//operator overloading
Point operator - () const; //negate the coordinates
Point operator * (double factor) const; //scale the coordinates
Point operator + (const Point& p) const; //add coordinates
bool operator == (const Point& p) const; //equally compare operator
Point& operator = (const Point& source); //assignment operator
Point& operator *= (double factor); //scale the coordinates and assign
friend std::ostream& operator << (std::ostream& os, const Point& p); //send to ostream (friend)
Shape& operator = (const Shape& source); // call assignment operator of base class
};
inline double Point::X() const //normal inline getter
{
return m_x;
}
inline double Point::Y() const //normal inline getter
{
return m_y;
}
}
}
#endif
Shape& Shape::operator = (const Shape& source) //assignment operator
{
if (this == &source) //avoid self-assignment
return *this;
cout << "shape assignment" << endl;
m_id = source.m_id;
return *this;
}
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
您的问题可能是您在命名空间中定义了 class,但是您在该命名空间之外定义了运算符而没有指定它。因此,编译器无法将定义连接到声明。
Ishamael 指出您没有指定将非点形状分配给点时会发生什么。这对于虚拟赋值运算符是必需的;看到他的回答。但是这个虚拟赋值运算符最终可能会做很多意想不到的事情,比如如果错误的类型被分配给彼此,就会切断部分对象。
您不需要虚拟性来确保在分配 Point 时也调用 Shape 运算符。只需在 Point 运算符中调用 Shape 运算符。使运算符虚拟化实际上会产生相反的效果; Point 运算符将覆盖 Shape 运算符,即使您调用它的实例被称为 Shape。
Point& Point::operator = (const Point& source) //assign
{
if (this == &source) //avoid self-assignment
return *this;
Shape::operator=(source); // also call the base class operator
m_x = source.m_x;
m_y = source.m_y;
return *this;
}
你的问题是,当你调用 operator =
并传递给它一个 Shape
时,你正在调用 Point::operator=(const Shape&)
,你没有定义它,你只定义了 Shape::operator=(const Shape&)
和 Point::operator=(const Point&)
。您需要添加 Point::operator=(const Shape&)
,例如:
Shape& Point::operator = (const Shape& shape) //assign
{
const Point& source = static_cast<Point&>(shape); // or use dynamic_cast here, if you want to be safe
if (this == &source) //avoid self-assignment
return *this;
m_x = source.m_x;
m_y = source.m_y;
return *this;
}