0

Is it possible to have a different type definition based on which derived class is instantiated?

Say I have a parent class with a virtual function func(), two int members and a vector of type myType, and two child classes, which share the same int members, and the vector, but their implementation of func() require myType to be slightly different.

For example:

class Parent {
  protected:
    int myMember;
    int myOtherMember;
    std::vector<myType> vec;

  public:
    Parent(variable);
    virtual int func() = 0;
}

class Child1 : public Parent {
  private:
    typedef <some type definiton> myType;

  public:
    Child1(variable) : Parent(variable){};
    int func() {return someFunc();};
}

class Child2 : public Parent {
  private:
    typedef <some other type definiton> myType;

  public:
    Child2(variable) : Parent(variable){};
    int func() {return someOtherFunc();};
}

Can I do something like this? when I have tried it, it creates a circular dependency in the header files, because class Parent is required to be included first, but then it requires myType to be defined.

Is there a way of forward declaring myType depending on class? or do I just need to include a different vector of myType in each class like so:

class Parent {
  protected:
    int myMember;
    int myOtherMember;

  public:
    Parent(variable);
    virtual int func() = 0;
}

class Child1 : public Parent {
  private:
    typedef <some type definiton> myType;
    std::vector<myType> vec;

  public:
    Child1(variable) : Parent(variable){};
    int func() {return someFunc();};
}

class Child2 : public Parent {
  private:
    typedef <some other type definiton> myType;
    std::vector<myType> vec;     

  public:
    Child2(variable) : Parent(variable){};
    int func() {return someOtherFunc();};
}
guskenny83
  • 1,321
  • 14
  • 27

3 Answers3

3

This is a job for templateman!

First we declare Parent

template <class TYPE>
class Parent {
  protected:
    int myMember;
    int myOtherMember;
    std::vector<TYPE> vec;

  public:
    Parent(TYPE variable);
    virtual int func() = 0;
};

Unfortunately a custom type contained within Child1 is out with this approach because the type needs to be declared before we can specialize a template on it. I'm using int and double here for ease. Replace as needed.

using Child1Type = int;
// or typedef int Child1Type; pre-C++11
class Child1 : public Parent<Child1Type> {
  public:
    Child1(Child1Type variable) : Parent(variable){};
    int func() {return someFunc();};
};

using Child2Type = double;
class Child2 : public Parent<Child2Type> {

  public:
    Child2(Child2Type variable) : Parent(variable){};
    int func() {return someOtherFunc();};
};

EDIT

Kicking myself for not getting this earlier (and burning way too much time because I knew it had to be possible, but was thinking in the wrong direction)

Declare the type up in Parent. Set the access based on who need to be able to see the type. Here I made Type public to test it out in main. The Type is declared in Parent and is visible to (and through because it's public) the Children.

Also stripped out everything that wasn't immediately necessary and used fixed width integer types so I could easily demonstrate the differences.

I think this is exactly what Pixelchemist was alluding to.

template <class TYPE>
class Parent {
  public:
    using Type = TYPE; // declare Type here
  protected:
    int myMember;
    int myOtherMember;
    std::vector<Type> vec; // visible here

  public:
    Parent(Type variable); // here
    virtual ~Parent(){}
    virtual int func() = 0;
};

class Child1 : public Parent<uint16_t> { // complicated type needs to be reproduced 
                                         // only once, here in the specialization
  public:
    Child1(Type variable) : Parent(variable){};
};

class Child2 : public Parent<uint32_t> {

  public:
    Child2(Type variable) : Parent(variable){};
};

int main()
{
    // and visible way down here in main through Child1 and Child2
    std::cout << "Child 1: " << sizeof(Child1::Type) << std::endl; 
    std::cout << "Child 2: " << sizeof(Child2::Type) << std::endl;
}

output is

Child 1: 2
Child 2: 4
user4581301
  • 33,082
  • 7
  • 33
  • 54
  • @guskenny83 if you see this, I finally figured out how to do *exactly* what you were after. I think. – user4581301 Jun 29 '16 at 01:59
  • One last question, when i bring the parent constructor out to parent.cpp, i get `parent.cpp:6:1: error: invalid use of template-name ‘Parent’ without an argument list Parent::Parent(int variable){`, but when i define exactly the same constructor in the header file, it is fine. – guskenny83 Jun 29 '16 at 02:13
  • You need to declare it something like this: `template Parent::Parent(int variable)`, but you rarely want to split the function declarations from the class declarations in a templated class and you almost never want to put the functions in a CPP file. Good explanation of why here: http://stackoverflow.com/questions/495021/why-can-templates-only-be-implemented-in-the-header-file – user4581301 Jun 29 '16 at 02:23
  • Thanks, i left the function definitions in the header and it worked fine! – guskenny83 Jun 29 '16 at 03:44
1

You could simply use templates:

template<class T>
struct Base
{
  std::vector<T> v;
};

struct D1 : public Base<int>
{
  // all stuff in here comes into play when deriving from Base is already done
  // Thus, compiler cannot know any typedefs from here inside Base...
};

struct D2 : public Base<double>
{
};

where you cannot use a typedef from derived in base class. See CRTP refer to typedef in derived class from base class.

Community
  • 1
  • 1
Pixelchemist
  • 24,090
  • 7
  • 47
  • 71
0

This is what templates are for:

<template typename T>
class Child : public Parent {
private:
    std::vector<T> vec;
public:
    Child(variable) : Parent(variable) {};
    int func() { return someOtherFunc(); };
}

Then Child is declared as something like:

Child<int> myChildInstance(10);
Assimilater
  • 944
  • 14
  • 33
  • Im still a bit confused as to where my typedef goes. Say `myType` is quite long and convoluted for each of Child1 and Child2? – guskenny83 Jun 29 '16 at 00:39
  • i would prefer not to have the `std::vector vec` in the Child class if possible, because in my actual scenario there are quite a lot of members like that – guskenny83 Jun 29 '16 at 00:44
  • @guskenny83 Sorry, I didn't catch that `myType` was part of your parent class. Looks like you have an answer now that suits you though – Assimilater Jun 29 '16 at 02:36