user8073659
user8073659

Reputation: 17

How to template static factory method?

how to template the below code? First, I have a Book as base:

class Book {
public:
    Book() {}
    ~Book() {}
}

Then ComputerBook:

class ComputerBook: public Book {
public:
    static ComputerBook* create() {
        return new ComputerBook();
    } 
private:
    ComputerBook ():Book() {}
}

Then PhoneBook:

class PhoneBook: public Book {
public:
    static PhoneBook* create() {
        return new PhoneBook();
    } 
private:
    PhoneBook():Book() {}
}

PhoneBook has two inheritances:

class PhoneBook1: public PhoneBook {
public:
    static PhoneBook1* create() {
        return new PhoneBook1();
    } 
private:
    PhoneBook1():PhoneBook() {}
}


class PhoneBook2: public PhoneBook {
public:
    static PhoneBook2* create() {
        return new PhoneBook2();
    } 
private:
    PhoneBook2():PhoneBook() {}
}

So that can merge ComputerBook and PhoneBook1, PhoneBook2 into one with template?

Upvotes: 1

Views: 2106

Answers (2)

Henri Menke
Henri Menke

Reputation: 10939

What you want is (probably) CRTP. You define your method create in the base class where it is parametrized with the derived class which is a template parameter. When inheriting from the template base you plug in the derived class and magically get the create function with the correct type.

I don't get why you have a private constructor or why you need this factory function at all though.

template < typename Derived >
class Book {
  friend Derived;
public:
  Book() {}
  ~Book() {}
  static Derived* create() {
    return new Derived{};
  }
};

class ComputerBook: public Book<ComputerBook> {
  // Make the base class a friend so we can access the private constructor
  friend class Book<ComputerBook>;
private:
  ComputerBook() : Book() {}
};

template < typename Derived >
class PhoneBook: public Book<Derived> {}; // no private constructor, no 'friend' needed

class PhoneBook1: public PhoneBook<PhoneBook1> {};
class PhoneBook2: public PhoneBook<PhoneBook2> {};

int main()
{
  auto cb = ComputerBook::create();
  auto pb1 = PhoneBook1::create();
  auto pb2 = PhoneBook2::create();
  delete cb;
  delete pb1;
  delete pb2;
}

Upvotes: 1

RazeLighter777
RazeLighter777

Reputation: 196

From what it looks like you are trying do do, you are making a static factory method called create for all of your books. You can templatize this method like this:

class Book {
public:
    Book() {}
    ~Book() {}
    template<typename T>
    static Book* create() {
        return new T();
    }
}

And then to make a phone book:

Book::create<PhoneBook1>();

Also make sure the constructors for each of the books are public, or friends of the Book::create static method.

Upvotes: 2

Related Questions