KillPinguin
KillPinguin

Reputation: 410

Allocating generic class in C++

I'm trying to write a Testbench that can test different implementations of an Interface. Coming from Java I would love to just specify an Interface, create some Classes that implement it and write a class Testbench<T extends MyInterface>

Transforming this approach to C++ gives something like:

// The Interface
class Animal {
public:
    Animal(int age) {};

    virtual ~Animal() {};
    virtual void Say();
};

// An Implementor
class Cow : Animal {
private:
    int age;

public:
    Cow(int age) : Animal(age) {
        this.age = age;
    };
    void Say() {
        std::cout << "I'm an " << age << " year old Cow" << std::endl;
    }
}

Next I define the templated class that can test different Animals:

template<> void AnimalTestbench<class T> {
   static void TestSay();
}

But when I try to implement the TestSay method, it gives me "Allocation of incomplete type T"

template<> void AnimalTestbench<class T>::TestSay() {
    T *animal = new T(5);
    animal->Say();
}

Of course I didn't specify that T should be an Animal, this is my first question. The latter is: why does this code fail?

I've heard that Templates are a fancy way for Macros that know about types, but if it's a Macro in a way, then the compiler should first replace T with my (complete) Type which he should be able to allocate and instantiate.

Upvotes: 1

Views: 170

Answers (2)

Silvano Cerza
Silvano Cerza

Reputation: 970

The correct syntax for template classes is:

template<typename T> void AnimalTestbench {
   static void TestSay();
}

And the method:

template<typename T> void AnimalTestbench<T>::TestSay() {
    T *animal = new T(5);
    animal->Say();
}

Upvotes: 0

AndyG
AndyG

Reputation: 41110

There are a number of issues with your code:

  • The Animal class should declare Say as pure virtual
  • The Animal class uses this. instead of this->
  • The Cow class does not derive publicly from Animal
  • The AnimalTestbench class does not use templates correctly, template<> defines a specialization, which is not what you want
  • T *animal = new T(5); is a memory leak, because a delete doesn't follow.
    • we don't need to allocate at all, actually

Fixed Animal class:

class Animal {
public:
    Animal(int) {};

    virtual ~Animal() {};
    virtual void Say() = 0;
};

Fixed Cow class:

class Cow : public Animal {
private:
    int age;

public:
    Cow(int age) : Animal(age) {
        this->age = age;
    };
    void Say() override{
        std::cout << "I'm an " << age << " year old Cow" << std::endl;
    }
};

Fixed AnimalTestbench (we don't need to separate the impl of TestSay from the declaration, but I'm following your approach:

template<class T>
struct AnimalTestbench
{
   static void TestSay();
};

template<class T>
void AnimalTestbench<T>::TestSay() {
    T animal(5);
    Animal *animal_base = &animal;
    animal_base->Say();
}

Usage:

int main()
{
    AnimalTestbench<Cow>::TestSay();
}

TestSay could be a standalone templated function, but I presume there are other virtual functions you wish to test and it's convenient to put them all in a single test class.

Demo

Upvotes: 4

Related Questions