0
votes

lets say i have a class with two std::string member and one int value, like:

class DataGroup final {
 public:
  explicit DataGroup (const std::vector<int>& groupNr,
                                   const std::string& group1,
                                   const std::string& group2)
      : groupNr(groupNr)
      , group1(group1)
      , group2(group2){};

  std::vector<int> groupNrs{};
  std::string group1{};
  std::string group2{};
};

Can i somehow have 2 overloaded constructors where one will initialize groupNr and group1, and other ctor initializes groupNr and group2 ? One of the strings not initialized in ctor call would be empty string then.

3
Could you show an example of how you would use this, i.e. how do you want to use the different constructors?cigien
You certainly can, but if you don't initialize any member variable explicitly, the compiler will generate default initialization for you. Relying on that may result to unexpected results.Hack06
@cigien it would be nice if i could call the constructor always with either one or the other string, i.e. int a = 2; int b = 3; std::vector<DataGroup > dataGroupList{}; dataGroupList.emplace_back(a, "Something for group1"); dataGroupList.emplace_back(b, "Something for group2");Bodega
But the first argument to your constructor expects a vector<int>, not an int.cigien

3 Answers

2
votes

There are several way to have expected behavior:

  • Named constructor

    class DataGroup final {
    public:
        // ...
        static DataGroup Group1(const std::vector<int>& groupNr,
                          const std::string& group)
          { return DataGroup{groupNr, group, ""}; }
        static DataGroup Group2(const std::vector<int>& groupNr,
                          const std::string& group)
          { return DataGroup{groupNr, "", group}; }
    
        // ...
    };
    
    DataGroup d = DataGroup::Group2({1, 2}, "MyGroup");
    
  • Tagged constructor

    struct group1{};
    struct group2{};
    class DataGroup final {
    public:
        // ...
        DataGroup(group1, const std::vector<int>& groupNr,
                          const std::string& group) : DataGroup{groupNr, group, ""} {}
        DataGroup(group2, const std::vector<int>& groupNr,
                          const std::string& group) : DataGroup{groupNr, "", group} {}
    
        // ...
    };
    
    DataGroup d{group2{}, {1, 2}, "MyGroup");
    
  • named parameters (see there for possible implementation)

    // ...
    DataGroup d{groupNr = {1, 2}, group2 = "MyGroup");
    
0
votes

For overloading a function/constructor, they must have 2 distinct signatures. Since your intended types to be supplied are the same for both cases, you have to supply a 3rd parameter with a possibly default value for one of them. But again, watch for uninitialized local fields, since they will be auto-initialized by the compiler-generated code.

0
votes

One of the solutions here would be to simply have base class with "common" member

groupNr(groupNr)

and other two separate member have in each derived class, then you would initialize base member groupNr by calling constructor of base class when initializing derived one:

class DataGroup {
 public:
  explicit DataGroup (const std::vector<int>& groupNrs)
      : groupNrs(groupNr){};

  std::vector<int> groupNrs{};
};

class DataGroup1 : public DataGroup {
 public:
  explicit DataGroup1 (const std::vector<int>& groupNrs,
                                   const std::string& group1)
      : DataGroup(groupNrs)
      , group1(group1){};

  std::string group1{};
};

class DataGroup2 : public DataGroup {
 public:
  explicit DataGroup2 (const std::vector<int>& groupNrs,
                                   const std::string& group2)
      : DataGroup(groupNrs)
      , group2(group2){};

  std::string group2{};
};