简体   繁体   中英

How to return a generic derived class from a virtual function?

I am writing a program that creates and manipulates shapes. The section of code I am having a problem with is below, specifically the return type of the virtual function translate in the polygon class. (this has been reduced for compactness)

    class polygon{
    public:
    virtual ~polygon(){};
    virtual class polygon translate() {};
    };

    class Itriangle : public matrix, polygon{  
   private:
      vector <matrix> vertices;  // vector of matrices 
      double centrex;
      double centrey;
      double sides;
   public:
   //Constructors (default/p const(points)/p const(centre and lengths))
   Itriangle(){};

   //Destructor
   ~Itriangle(){};

   //Functions from interface

   Itriangle translate(class matrix &m){
      . . .
   Itriangle translated (transCx, transCy, a, b, c);
       return translated ;
   } 

I then go on to derive several other shapes from the polygon class.

The problem I am having with it is that I want the translate function to be able to return any class that is derived from polygon.

I have tried to use points and a template but I am unsure about both.

Any help would be great.

You're referring to a notion that's called covariant return type .

Since a return type of a function is not a part of its signature you can return a derived type of a base's return type in a polymorphic method as long as its a pointer or a reference .

In your case, a pointer (or a reference) to Itriangle.

class polygon {
public:
    polygon *translate(class matrix &m) {
       return new polygon(...);
    }
};

class Itriangle : public matrix, polygon {
public:
    Itriangle *translate(class matrix &m) {
       return new Itriangle(...);
    }
};

Note that it can't be created on the translate method's stack, if you want to return it back. Meaning, you'll have to allocate it using new .

In general a reference is also possible for achieving this but in your case since the ITriange is created inside the translate(...) method, it would be problematic (whether it is created on the stack and the reference would point to unallocated memory, or it is allocated on the heap and no one knows it needs to be deleted since it's a reference).
If for example, you were returning a member of the class, then you would be able to use a reference.


I've created a dummy app for you to see it in action:

#include <iostream>

using namespace std;

class polygon {
public:
    virtual polygon *translate(int x) {
        cout << "polygon!" << endl;
       return new polygon();
    }
};

class Itriangle : public polygon {
public:
    Itriangle *translate(int x) {
        cout << "triangle!" << endl;
       return new Itriangle();
    }
};

int main() {
    polygon p;
    Itriangle t;
    polygon &pt = t;

    p.translate(1);
    t.translate(2);
    pt.translate(3);
}

This prints:

polygon!
triangle!
triangle!


By the way, I noticed an error in your code.

your Itriangle is defined:

class Itriangle : public matrix, polygon {
    ...
};

which means you're privately inheriting polygon. That is very rarely what you want to do.
I'm guessing you ment:

class Itriangle : public matrix, public polygon {
    ...
};

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM