friend operator with polymorphic behavior

Started by
4 comments, last by johnstanp 15 years, 11 months ago
Well,I've derived aclass from an abstract one and I want to define a friend function( operator<< ) that would be polymorphic. Here are the specs of the classes:

#ifndef SHAPE_HPP
#define SHAPE_HPP

#include <iostream>
#include <fstream>

using std::ostream;
using std::ofstream;

class Shape
{
      public:
             
             Shape();
             ~Shape();
             
             virtual void draw()const=0;
};

Shape::Shape()
{
}

Shape::~Shape()
{
}

#endif



And the derived class:

#ifndef RECTANGLE_HPP
#define RECTANGLE_HPP

#include <iostream>
#include <fstream>
#include <vector>
#include <GL/GL.h>
#include <GL/glu.h>
#include "Vector3D.hpp"
#include "Shape.hpp"

using std::vector;
using std::ostream;
using std::ofstream;
using std::cout;
using std::endl;

template<class T>
class Rectangle : public Shape
{
      public:
             
             Rectangle();
             Rectangle( const T& , const T& ); 
             ~Rectangle();
             
             void draw()const;
             
             template<class U> friend ostream& operator<<( ostream& , const Rectangle<U>& );
             template<class U> friend ofstream& operator<<( ofstream& , const Rectangle<U>& );
             
      protected:
                
                T a;
                T b;
                vector<Vector3<T> > vertices;
};

template<class T>
Rectangle<T>::Rectangle()
{
}

template<class T>
Rectangle<T>::Rectangle( const T& _a , const T& _b )
{
    a = _a;
    b = _b;
    
    vertices.reserve( 4 );
    vertices.push_back( Vector3<T>( -a/2 , -b/2 , 0 ) );
    vertices.push_back( Vector3<T>( a/2 , -b/2 , 0 ) );
    vertices.push_back( Vector3<T>( a/2 , b/2 , 0 ) );
    vertices.push_back( Vector3<T>( -a/2 , b/2 , 0 ) );
}
    
template<class T>
Rectangle<T>::~Rectangle()
{
}

template<class T>
void Rectangle<T>::draw()const
{
}

template<class T>
ostream& operator<<( ostream& out , const Rectangle<T>& s )
{
    for( int i = 0 ; i < 4 ; ++i )
    {
        out << i << ":(" << s.vertices[0] << "," << s.vertices[1] << "," << s.vertices[2] << ")" << endl;
    }
    
    return out;
}

template<class T>
ofstream& operator<<( ofstream& out , const Rectangle<T>& s )
{
    for( int i = 0 ; i < 4 ; ++i )
    {
        out << i << ":(" << s.vertices[0] << "," << s.vertices[1] << "," << s.vertices[2] << ")" << endl;
    }
    
    return out;
}
                      
template<>
void Rectangle<float>::draw()const
{
    glBegin( GL_QUADS );
        glVertex3f( vertices[0][0] , vertices[0][1] , vertices[0][2] );
        glVertex3f( vertices[1][0] , vertices[1][1] , vertices[1][2] );
        glVertex3f( vertices[2][0] , vertices[2][1] , vertices[2][2] );
        glVertex3f( vertices[3][0] , vertices[3][1] , vertices[3][2] );  
    glEnd(); 
}
                      
template<>
void Rectangle<double>::draw()const
{
    glBegin( GL_QUADS );
        glVertex3d( vertices[0][0] , vertices[0][1] , vertices[0][2] );
        glVertex3d( vertices[1][0] , vertices[1][1] , vertices[1][2] );
        glVertex3d( vertices[2][0] , vertices[2][1] , vertices[2][2] );
        glVertex3d( vertices[3][0] , vertices[3][1] , vertices[3][2] );  
    glEnd(); 
}

#endif



I want actually this: Shape* s = new Rectangle<double>( 50.0 , 20.0 ); cout << s << endl; How can I achieve this? [Edited by - johnstanp on May 6, 2008 6:29:14 AM]
Advertisement
You could define a (pure) virtual function in your base class that does the outputting into the stream and then define global operator<<(std::ostream&, Base const&) that would call this function — it doesn’t even have to be friend this way. E.g.:
#include <iostream>class Base {public:  virtual ~Base() { }  virtual void print(std::ostream&) const = 0;};template <typename T>class Derived  : public Base{public:  Derived(T a, T b);  virtual void print(std::ostream& stream) const;private:  T a;  T b;};template <typename T>Derived<T>::Derived(T a, T b)  : a(a)  , b(b){ }template <typename T>void Derived<T>::print(std::ostream& stream) const {  stream << '[' << a << "; " << b << ']';}std::ostream& operator<<(std::ostream& stream, Base const& b) {  b.print(stream);  return stream;}int main() {  Base* b = new Derived<double>(3.14, 2.71);  std::cout << *b << '\n';  delete b;}
Quote:Original post by Oxyd
You could define a (pure) virtual function in your base class that does the outputting into the stream and then define global operator<<(std::ostream&, Base const&) that would call this function — it doesn’t even have to be friend this way. E.g.:*** Source Snippet Removed ***


I like your solution:simple,clean and elegant.
I'll code it.

Thanks for being that quick to answer.

PS:what are the tags to use for "code quoting"?
Quote:Original post by johnstanp
PS:what are the tags to use for "code quoting"?


You can put larger code snippets in [source] [/source] tags and smaller ones in [code] [/code] tags — the latter only gives you monospaced font, without hilighting or scrollable frame. x)
Quote:Original post by johnstanp
PS:what are the tags to use for "code quoting"?


Read the FAQ for nice formatting tips
English is not my native language.Sam.
Quote:Original post by rolkA
Quote:Original post by johnstanp
PS:what are the tags to use for "code quoting"?


Read the FAQ for nice formatting tips


Thanks...I'm so lazy. lol

This topic is closed to new replies.

Advertisement