C ++虚拟赋值运算符

时间:2015-02-02 05:45:02

标签: c++ virtual assignment-operator

我试图从派生类(point)中的基类(shape)调用赋值运算符。我得到一个未解决的外部链接器错误,我不明白为什么。我把"虚拟"在基本赋值运算符的前面,并在最后将基本赋值运算符放在派生类的内部。我哪里做错了?

#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;
        }

2 个答案:

答案 0 :(得分:3)

您的问题是,当您拨打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;
    }

答案 1 :(得分:1)

您的问题可能是您在命名空间中定义了类,但您在该命名空间之外定义了运算符而未指定它。因此,编译器无法将定义连接到声明。

Ishamael指出,您没有指定将非点形状分配给Point时会发生什么。这对于虚拟赋值运算符是必需的;看到他的回答。但是这个虚拟赋值运算符最终可能会做很多意想不到的事情,比如如果错误的类型被分配给对方,就会切断部分对象。

您不需要虚拟性来确保在分配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;
    }