0

I would like to be able to initialize a class member in one of N ways (in this examples N=2) based on a condition that is recieved via the class constructor as in the code that follows, but the MainObject's initialization seems to be only local to the (container) class' constructor. I wonder what are the best-practices for this particular pattern.

// in ContainerObject.hpp

class ContainerObject {
public:
    MainClass MainObject;
    ContainerObject(int type);
}



// in ContainerObject.cpp

ContainerObject::ContainerObject(int type);{
    if (type == 0){
        MainObject("something", 1, 2);
    } else if (type == 1){
        MainObject(4, "another thing", "yet another thing");
    }
}

I have so-far thought about

  1. putting the main object in the heap
  2. defining N class constructors and call the appropiate one recursively inside the "main"/"first" class constructor.

please note that the "0" and "1" initialization is only an example and it could be drastically different.

EDIT1: added ";" required for compiling EDIT2: Changed the original

//...
if (type == 0){
    MainObject(0);
} else if (type == 1){
    MainObject(1);
}
//...

for the current one

//...
if (type == 0){
    MainObject("something", 1, 2);
} else if (type == 1){
    MainObject(4, "another thing", "yet another thing");
}
//...

as it was called a duplicate by being misinterpreted for a case that could be solved by adding the following.

//...
ContainerObject(int type): MainObject(type);
//...
Gaston
  • 537
  • 4
  • 10
  • Duplicate? https://stackoverflow.com/questions/1711990/what-is-this-weird-colon-member-syntax-in-the-constructor – πάντα ῥεῖ Oct 29 '21 at 14:48
  • Beides that, you have an excess `;` after the signature in the constructor definition. – πάντα ῥεῖ Oct 29 '21 at 14:50
  • Indeed the question mentions "N" possible types, so it's a matter of extending the conditional clause to include `type == 2`, ..., `type == N-1` and adding some realistic error handling if type exceeds "N". – Gaston Oct 29 '21 at 15:05

2 Answers2

2

I am interpreting the question as "how to perform non-trivial logic before/during the member initialization list".

A good way to go about that is to delegate the work of converting the constructor parameter of the outer object into the child object to a utility function:

// in ContainerObject.cpp

#include <stdexcept> // for std::invalid_argument

// Anonymous namespace since main_factory() is only needed in this TU.
namespace {

MainClass main_factory(int type) {
  if (type == 0) {
    return MainClass("something", 1, 2);
  } else if (type == 1) {
    return MainClass(4, "another thing", "yet another thing");
  }

  // N.B. This is one of the scenarios where exceptions are indisputably
  // the best way to do error handling.
  throw std::invalid_argument("invalid type for MainClass");
}

}

ContainerObject::ContainerObject(int type) 
  : MainObject(main_factory(type)) {}

  • Please note the question states `please note that the "0" and "1" initialization is only an example and it could be drastically different.`. In particular it could require different amount and type of objects depending on each type. – Gaston Oct 29 '21 at 15:03
  • 1
    @Gaston: that why there is `foo` and not directly `MainObject(type)`. `foo` might even return a `MainClass`. – Jarod42 Oct 29 '21 at 15:05
  • Could you please show a function that provides `MainObject`'s constructor with two possible inputs as required now, after EDIT2? – Gaston Oct 29 '21 at 15:13
  • @Gaston I updated the answer to match the updated question. –  Oct 29 '21 at 15:15
  • Is there a workaround to `MainClass` not being copyable because of its constructor being private? – Gaston Oct 29 '21 at 17:30
  • @Gaston Simply set your compiler flags to C++17 or above, and something called mandatory copy elision will remove the need for a copy/move constructor. –  Oct 29 '21 at 17:36
1

A constructor is always called automatically whenever an object is created. You can never call it by yourself anywhere.

Ted Lyngmo
  • 93,841
  • 5
  • 60
  • 108