0

I have an abstract base class, and multiple objects that might inherit from it. For instance

    class Mode {
        public:
        int n,l,m;
        double omega;
        virtual int doSomething() =0;
        virtual ~Mode(){};
    }

    class ModeA : Mode {
        ModeA(int N, int L, int M);
        ModeA(double W, int L, int M);
        virtual ~ModeA();
        int doSomething();
    }

    class ModeB : Mode {
        ModeB(int N, int L, int M);
        ModeB(double W, int l, int M);
        virtual ~ModeB();
        int doSomething();
    }    

The two child classes, ModeA and ModeB have constructors with parameters (int, int, int) and (double, int, int). Later, I have a piece of code that expects as Mode object, which looks like

    template <class MODE> int mode_finder(MODE** mode_list, int num_mode, int N, int L, int M){
        assert((std::is_base_of<Mode,MODE>::value));
        for(int i=0; i<num_mode; i++){
            mode_list[i] = new MODE(N,L,M);
             ... some more code here ...
        }
    }

(this isn't simply a function to initialize a list of modes, the ...some more code here... part is about 300 lines long and includes checking values against a list and deleting and recreating if they don't match -- a lot of stuff has been left out of this simple working example)

If I'm using ModeA and ModeB, then this is fine, because they have the right kind of constructors.

My problem is that I (or whoever inherits this code) might eventually make a new type and forget to put in constructors of this form, such as

    class ModeC : Mode {
        ModeC(int X);
        virtual ~modeC();
        int doSomething();
    }

This will create run-time errors if I call mode_maker with ModeC, when the function template for ModeC is created.

I want for every object to inherit from Mode to implement constructors with two signatures: a (int, int, int) and (double, int, int) form. If not, I want to throw a compile-time error.

I assumed pure virtual constructors would do the trick, something like:

    virtual Mode(int, int, int) =0;
    virtual Mode(double, int, int) =0;

but apparently that isn't a language feature due to vtable issues. I don't really need entries on the vtable for anything, I just need the child classes to be forced to make constructors of this type.

How can I do the thing I'm trying to do?

Thanks in advance.

RBoston
  • 33
  • 6
  • Related: https://stackoverflow.com/questions/13787901/ensure-derived-class-constructor-must-call-specific-base-class-method – πάντα ῥεῖ Jul 03 '19 at 16:47
  • If you try using a function template and that type doesn't have a specific function or constructor, that will result in a compile-time error, not a runtime error. Also, if you want to be notified of things at compiletime, you should use the static_assert construct, which will prevent compilation if there's an error: static_assert(test(), "Message") – Alecto Irene Perez Jul 03 '19 at 16:48
  • 1
    You may add those constructor signatures (`protected`) to your abstract base class, thus the derived classes at least need to provide one of them. – πάντα ῥεῖ Jul 03 '19 at 16:49
  • Thanks, I saw that (and many others) in my searches before asking. I don't have a problem with calling a parent method from a child class, I have an issue with needing a way to create compile errors if a child class doesn't have a specific constructor signature. – RBoston Jul 03 '19 at 16:51
  • Thanks J. Antonio. I tried using `static_assert()`, but there's some other issue with the g++ compiler. I thought function templates only made the functions at run time when needed? What would even be the test to pass to `static_asser()`? – RBoston Jul 03 '19 at 16:53
  • Re: "apparently that isn't a language feature due to vtable issues" -- that's not the reason. It would certainly be possible to implement something that allowed you to declare a constructor as virtual, but it's not at all clear what that would mean. A virtual function is dispatched according to the type of the object that it's being called on. A constructor creates a new object; until the constructor has finished running the object doesn't exist. – Pete Becker Jul 03 '19 at 18:29
  • _"This will create run-time errors"_ -- could you describe the runtime errors you see when you try this? :innocent: – JaMiT Jul 03 '19 at 23:40

1 Answers1

0

This will create run-time errors if I call mode_maker with ModeC, when the function template for ModeC is created.

No it won't. Templates are checked at compile time.

Template functions generate functions at compile time. Template classes generate classes at compile time.

You may be confused by generics in Java/C#, which where inspired by and serve some of the purposes of templates, and are far more runtime based.

C++'s equivalent of Generics is type erasure classes like std function. This uses templates to create the glue code that Java/C# language does for you when you interact with Generics, roughly. I would consider doing this (creating type eraser helper types, as opposed to just using std function) to be an advanced use of C++. There are some uses of Generics in Java/C# that require this in C++; most uses.of Generics, however, can be emulated in C++ by bog standard template code.

Yakk - Adam Nevraumont
  • 262,606
  • 27
  • 330
  • 524