Skip to main content
GameDev.net gamedev.net
🔒 Locked

templated virtual operator() (solved)

Started by thedustbustr Dec 23, 2004 at 5:11 PM 5 replies 400+ views
Original Post
thedustbustr
thedustbustr
I want to define operator<< so that I can do std::cout << (*e) << std::endl; EventArg is a templated class which derives from EventArgBase
class EventArgBase 
{
public:
    //void operator()(){} //void does not have operator<< defined
    std::string operator()(){return "";}
    virtual std::string dump() 
    { std::stringstream s; return s.str(); }
};
template<typename Elem, typename Traits> 
std::basic_ostream<Elem,Traits>& operator<<
(std::basic_ostream<Elem,Traits>& out, const EventArgBase& in)
{return out << "(" << in() << ")";}

template<typename T>
class EventArg : public EventArgBase
{
public:
    T t;
    EventArg(T _t) {t=_t;}
    T operator()() {return t;}
    std::string dump() 
    { std::stringstream s; s<<(*this)(); return s.str(); }
};


class Event
{
public:
    std::string type;
    double time;
    double true_time;
    EventArgBase* arg;

    Event(std::string t, EventArgBase* a=new EventArgBase(), double when=0);
    ~Event();
};
template<typename Elem, typename Traits> 
std::basic_ostream<Elem,Traits>& operator<<
(std::basic_ostream<Elem,Traits>& out, const Event& in)
{return out << in.type << " (" << (*in.arg)() << ")"  ;}

/*...*/
Event* e = new Event("foo", new EventArg<std::string>("arg"));
std::cout << (*e) << std::endl;

The code at the bottom should print "foo (arg)" but instead prints "foo ()". Soooo... what did I do wrong? I thought I had this :( [Edited by - thedustbustr on December 23, 2004 10:57:33 PM]
Extrarius
Extrarius
When you're using a pointer to a base class and want to call functions of the derived classes without casting the pointer, the functions you're calling that way must be declared virtual. In this case, that means make operator() virtual in both EventArgBase and EventArg
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
thedustbustr
thedustbustr
I could have sworn that once the base class declares it virtual then it is virtual for the rest of the derived classes automatically. [edit] Tested making the derived dump function virtual, no good. Making operator() virtual is pointless because the base operator() and the derived operator() have diferent signatures- the latter is templated.
thedustbustr
thedustbustr
I understand why operator() SHOULD be virtual: Event::arg is stored as a pointer to EventArgBase, but it is really an EventArg*. Calling Event::arg::operator() calls the base class because operator() is not virtual. HOWEVER, if I declare operator() virtual, I get this error because the second operator() is templated.
error C2555: 'EventArg::operator()'': overriding virtual function return type differs and is not covariant from 'EventArgBase::operator()''
How do I work around this?
Extrarius
Extrarius
If you don't make the operator() virtual, you can't call it through a base pointer as you do in operator<<(stream,Event) unless the base pointer always only points to the base class. Perhaps you meant to call the dump function there instead?

You are correct that the virtual attribute is automatically propogated down the inheritence chain, but you're not calling any virtual functions that I see in your code so that fact doesn't matter. You're calling operator() on a base pointer that points to a derived class when operator() isn't virtual, which afaik means undefined behavior.

Edit: I started this post before your last post. The only real solution I see is using dump() inside operator<<(stream,Event)
You really shouldn't do what you're doing with operator(), but I'm not sure how to achieve the same effect the 'proper' way.
"Walk not the trodden path, for it has borne it's burden." -John, Flying Monk
thedustbustr
thedustbustr
So is calling operator() on my derived pointer still undefined? I'm currently working on what you suggested.
thedustbustr
thedustbustr
I used your dump inside operator<< (I was thinking about that before you posted anyway) and it worked. operator() isn't virtual anymore. Thanks Extrarius

Topic Locked

This topic has been locked by a moderator. New replies are not allowed.

Sign in to reply to this topic.