how to create array of an abstract class in c++

2020-04-07 04:20发布

I am trying to create a program that takes food order and prints it out. I have my base class Food which has a pure virtual function in it. Class Food has 2 subclass Pizza and Dessert. I am trying to make an array of Food in my main so when a customer orders Pizza or Dessert, it will be stored in the array of Food. But every time I try, I get an error. How should I put the two items together then if I want to use a loop to go over each item the customer ordered? This is my code:

int main()
{
  Dessert d("brownie");
  Pizza p("BBQ delux");
  Food array[2] = {d,p};
}

This is my error message. (NOTE: get_set_price() and print_food() are my pure virtual functions which is defined in base class and implemented in the 2 subclasses)

main.cpp:37:14: error: invalid abstract type ‘Food’ for ‘array’
  Food array[2] = {d,p};

In file included from main.cpp:4:0:
Food.h:5:7: note:   because the following virtual functions are pure within ‘Food’:
 class Food
       ^

Food.h:20:15: note:     virtual void Food::get_set_price()
  virtual void get_set_price()=0;
               ^

Food.h:27:15: note:     virtual void Food::print_food()
  virtual void print_food()=0; 
               ^

main.cpp:37:22: error: cannot allocate an object of abstract type ‘Food’
  Food array[2] = {f,o};
                  ^

4条回答
看我几分像从前
2楼-- · 2020-04-07 05:10

You cannot create instances of abstract classes, but you can assign concrete derived instances to pointers or references of the base class.

int main()
{
  Dessert d("brownie");
  Pizza p("BBQ delux");
  Food* array[2] = {&d,&p};
}

then work with array

array[0]->print_food();
查看更多
趁早两清
3楼-- · 2020-04-07 05:10

You need reference semantics for that, because Food arr[2]; tries to initialize the array with default values (which are abstract, thus not constructible).

I think std::array<std::unique_ptr<Food>, 2> arr; should be the most natural to use in this case.

std::array<std::unique_ptr<Food>> arr = {
    std::make_unique<Dessert>("brownie"),
    std::make_unique<Pizza>("BBQ delux")
};

If you just want to loop over those two values, though, using initializer_list would be easiest, I suppose.

for (auto f : std::initializer_list<Food*>{&d,&p})
    f->commonMemberFunction();

Unfortunately it won't deduce the correct type from just {}, but a helper could be created, I suppose,

查看更多
看我几分像从前
4楼-- · 2020-04-07 05:17

Starting with C++11, you can use std::reference_wrapper too. It's very similar to @Mykola's answer, but uses references:

#include <functional>  // for std::reference_wrapper

int main()
{
  Dessert d("brownie");
  Pizza p("BBQ delux");
  std::reference_wrapper<Food> array = {d, p};

  // just to see they're references, they have same memory addresses as
  // the initial variables.
  for (const Food &f : array) {
    std::cout << &f << " ";
  }
  std::cout << "\n" << &d << " " << &p << "\n";
}

Unfortunately the same restriction applies to this and to the version with pointers. You need to have local variables defined, you can't just use anonymous objects here.

This won't work:

  std::reference_wrapper<Food> array = {Dessert("brownie"), Pizza("BBQ delux")};
查看更多
来,给爷笑一个
5楼-- · 2020-04-07 05:18

I like the simplicity of the answer from @Mykola. However, I prefer the look of the following:

int main()
{
  Food* array[] = {
    new Dessert("brownie"),
    new Pizza("BBQ delux")
    };
}
查看更多
登录 后发表回答