2015-02-02 3 views
0

Я пытаюсь вызвать оператор присваивания из базового класса (формы) в производном классе (точке). Я получаю нерешенную ошибку внешнего компоновщика, и я не понимаю, почему. Я поставил «виртуальный» перед оператором базового присваивания и поместил оператор базового присваивания внутри моего производного класса в конце. Где я неправ?Оператор виртуального присваивания C++

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

Где находятся определения ваших операций назначения? – Ishamael

+0

У вас есть аналогичное определение для 'Point :: operator = (const Shape &)'? – Ishamael

ответ

1

Ваша проблема может быть, что вы определяете класс в пространстве имен, но можно определить операторы вне этого пространства имен без указания его. Из-за этого компилятор не может подключить определение к объявлению.

Ishamael указал, что вы не указываете, что происходит, когда неточная точка назначается точке. Это необходимо для оператора виртуального присваивания; см. его ответ. Но этот виртуальный оператор присваивания может в конечном итоге сделать много неожиданных вещей, например, отрезать части объектов, если неправильные типы назначены друг другу.

Вам не нужна виртуальность, чтобы оператор Shape также вызывался при назначении Point. Просто вызовите оператор Shape внутри оператора Point. Сделать виртуальный оператор фактически имеет противоположный эффект; оператор 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; 
    } 
+0

Спасибо, я до сих пор получаю ошибку при добавлении «= 0» в конец. Это определение находится в нижней части главного сообщения. – kits

+0

Да, я видел ваши изменения и соответственно менял свой ответ. Помогает ли это определить пространство имен? – jack

+0

У меня есть проект с инструкцией «Оператор присваивания должен вызывать оператор присваивания базового класса Shape. В противном случае данные формы не будут скопированы. Вот почему я использую виртуальный – kits

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; 
    } 
Смежные вопросы