Home > other >  How to write a method with an unknown type of return value in abstract class in C ?
How to write a method with an unknown type of return value in abstract class in C ?

Time:06-01

For example, I now have two structs.

struct Point_2d {
    int x, y;
};

struct Point_3d {
    int x, y, z;
};

And thus I've made two classes.

class Graph_2d {
public:
    Point_2d getFirstPoint(int a);
};

class Graph_3d {
public:
    Point_3d getFirstPoint(int a);
};

And now I want these two classes to be inherited from a abstract class, like so:

class Graph {
public:
    virtual ??? getFirstPoint(int a); // just define interface
};

class Graph_2d: public Graph {
public:
    Point_2d getFirstPoint(int a) {
         // implementation here
    }
};

// Graph_3d the same

wonder what to place in ???, I've tried use template <typename T> virtual T getFirstPoint(); but that didn't work.

I may don't want to use template class like template <typename T> class Graph;, but template method is acceptable. And Point_2d and Point_3d must be struct but not class.

Is there a way to correct it literally(grammarly) or do I must refactorizing?

Any reply is fervently anticipated. (Sorry for my poor English, I'm not a native English speaker but I'm trying to explain everything I need clearly.)

CodePudding user response:

You should absolutely take to heart everything said in the comments, the biggest question you need to answer for yourself here is exactly why you're trying to do things this way, and if it's really the right approach. BUT in the spirit of just giving you an answer to the question you asked, the piece you're missing is that if you're going to use abstraction on the getter, you need an abstract data type.

You can do something like this with pretty much zero overhead:

struct Point {
    int x, y;
};

typedef Point Point_2d;

struct Point_3d : public Point {
    int z;
};

class Graph {
public:
    virtual Point *getFirstPoint(int a);
};

class Graph_3d: public Graph {
public:
    Point *getFirstPoint(int a) override {
         return &points_[0];
    }
    Point_3d points_[20];
};

Of course this says nothing about exactly how you plan to use this. Any caller of getFirstPoint() will need to know exactly what type is being returned in order to up or downcast it, but I believe it satisfies your requirement as written.

CodePudding user response:

First of all, you should reconsider your design. Thinks about something like std::variant<Point_2d, Point_3d> getFirstPoint(int a) check out std::variant

I'm just posting this code in case you REALLY want to do things this way.

#include <iostream>

struct point2d {
    int x, y;
};

struct point3d {
    int x, y, z;
};

template <typename T>
class GraphCommon{
public:
    void commonMethod() {std::cout << "Common methonds goes in this class\n";}
    virtual T getPoint(int a){}
};

template <typename T>
class Graph : public GraphCommon<T> {
public:
    virtual void notPureVirtual() {std::cout << "virtual functions goes here\n";}
    T getPoint() {std::cout << "base class\n";}
};

template<>
class Graph<point2d> : public GraphCommon<point2d> {
public:
    point2d getPoint(int a) override {std::cout << "2D pint is returned\n";}
};

template<>
class Graph<point3d> : public GraphCommon<point3d> {
public:
    point3d getPoint(int a) override {std::cout << "3D point is returned\n";}
};

int main() {

    Graph<point2d> p1;
    Graph<point3d> p2;
    p1.getPoint(1);
    p1.commonMethod();
    p2.getPoint(1);
    p2.commonMethod();
    p1.notPureVirtual() //Error, notPureVirtual() is not specialized for Graph<point2d>

    Graph<float> f;
    f.getPoint();
    f.notPureVirtual(); //But it works for Grapth<T>
    return 0;
}

The class GraphCommon is for the common functions between the specialized classes, without it you will have to redefine all the functions for each specialization even if you will not change them.

  • Related