-4

I have a class with a hidden default constructor to force the use of a constructor taking parameters. Another class is using 2 instances of the class:

typedef struct { ... } BAZ;

class Foo {
  private:
    Foo(void) {}

  public:
    Foo(BAZ a) { ... }
};

class Bar {
  private:
    Foo foo1;
    Foo foo2;

    Bar(void) {}

  public:
    Bar(BAZ a, BAZ b) : foo1(a), foo2(b) { ... }
};

The most obvious is that the declaration of the variables foo1 and foo2 will call the default Foo constructor, but since it is private it can't and will give a compiler error.

Is there a way to prevent it from trying the default Foo constructor and just wait for the Bar constructor to initialise them instead?

I want to avoid the use of the new keyword (which would solve the whole problem).

EDIT:
It seems like people have a hard time to understand the question and dilemma. I will try to explain:

I want to force the use of a Foo(BAZ) constructor meaning that any attempt to use the Foo(void) constructor will generate an error.

To hide the default constructor it is declared as a private member. If someone try to use the default constructor Foo() it will give an intentional error.

To not declare the default constructor and only declare Foo(BAZ) is not preventing the compiler to create a public default constructor. It gives no error if I declare it Foo(). So far it works fine and as intended.

The second class Bar have two instances of Foo but when Bar is instanced these Foo members will be called with the default (hidden) constructor and generate an error. Then in the Bar constructor, these two instances will be initialized with the correct public constructor Bar(BAZ a, BAZ b) : foo1(a), foo2(b). This is what I want.

Is there a way to prevent it from calling Foo default constructor when Bar is initialized, so the Bar constructor can use the correct Foo constructor?

The new solution works because the default constructor is never called:

BAZ a = {...}
Foo *foo1 = new Foo(a);

I hope this makes it more clear.

EDIT2: SOLVED The error wasn't in the hidden Foo constructor, it was the hidden Bar constructor trying to use the hidden default Foo constructors.

Bar(void) : Foo(BAZ{}), Foo(BAZ{}) {}

Solved it.

EDIT3:
The real problem seems to have been in the development tool. After restart and manually clearing the cache it worked as the C++14 standard intended.

Cœur
  • 37,241
  • 25
  • 195
  • 267
Max Kielland
  • 5,627
  • 9
  • 60
  • 95
  • 2
    If you don't want it to be used why are you defining it? – StoryTeller - Unslander Monica Dec 01 '17 at 18:39
  • It is called a hidden constructor to prevent it from being used (hence in the private section). If I don't, the compiler will create a public default constructor and will not give a warning if someone use it. – Max Kielland Dec 01 '17 at 18:40
  • 6
    The mere act of declaring **any c'tor** prevents the generation of the implicit default one. That's C++ 101. – StoryTeller - Unslander Monica Dec 01 '17 at 18:41
  • 4
    Do not do `typedef struct` crap in C++, that is a bad habbit from C. – Slava Dec 01 '17 at 18:43
  • 1
    btw I dont see how using `new` would solve anything – 463035818_is_not_an_ai Dec 01 '17 at 18:46
  • @Story Teller. Not true I just tried to remove the default constructor and guess what, I could still declare Foo foo1; without compiler errors. It is declared private so it cant be declared as Foo foo1; – Max Kielland Dec 01 '17 at 18:47
  • Are you asking how to create a default constructor for `Bar` that doesn't generate an error? – Mark Ransom Dec 01 '17 at 18:48
  • 1
    imho this question needs some clarification. Lets start with one random detail: the declaration of the members `foo1` and `foo2` alone will not call any constructor. Do you mean that `Bar(void){}` causes an error because it tries to call `Foo`s default constructor for those members? – 463035818_is_not_an_ai Dec 01 '17 at 18:53
  • 2
    @MaxKielland without errors? That's not what happens when I do it: https://ideone.com/ZHBwlK – Mark Ransom Dec 01 '17 at 18:56
  • P.S. If your compiler doesn't generate an error with my quick test code, you need a better compiler that conforms to the standards. – Mark Ransom Dec 01 '17 at 19:09
  • As my tag indicates I'm using Atmel Studio. This is a development environment for embedded programming based on a modified GNU compiler. There might be a different non standard implementation or just simply a bug. – Max Kielland Dec 01 '17 at 19:15

2 Answers2

6

the declaration of the variables foo1 and foo2 will call the default Foo constructor

No. Declaring these member variables only says that they are members. It doesn't say anything about how they will be constructed. That's the job of the constructor(s) of the class that uses them.

Bar(BAZ a, BAZ b) : foo1(a), foo2(b) { ... }

Fine so far: this constructor constructs the foo1 and foo2 members using the constructor Foo(Baz).

Bar(void) {}

This is the problem: it attempts to construct the foo1 and foo2 members with the default constructor for Foo. Since that constructor is not accessible (that's the correct term; it is not hidden), you get an error. There are at least three solutions:

1:

Bar() : foo1(Baz()), foo2(Baz()) {}

This uses the constructor that takes Baz.

2:

Bar() = delete;

This makes the default constructor for Bar not exist, so it doesn't try to use the default constructor for Foo.

3:

Just don't do it. If you don't write a default constructor but you do write another one, the compiler won't generate a default constructor.

Pete Becker
  • 74,985
  • 8
  • 76
  • 165
  • I came to the same conclusion while you answered :) This compiler seems to always declare a default constructor, but I will try the delete statement instead. – Max Kielland Dec 01 '17 at 19:28
  • Foo(void) = delete; worked after I restarted and cleared the cache. It seems to have been a partially cache problem in the development tool. – Max Kielland Dec 01 '17 at 19:50
5

Don't hide constructors. Don't declare them in the first place.

typedef struct { ... } BAZ;

class Foo {
  public:
    Foo(BAZ a) { ... }
};

class Bar {
  private:
    Foo foo1;
    Foo foo2;

  public:
    Bar(BAZ a, BAZ b) : foo1(a), foo2(b) { ... }
};
Sebastian Redl
  • 69,373
  • 8
  • 123
  • 157
  • 2
    Or, for C++11, explicitly delete them, `public: Foo() = delete;`. That'll inform people that the default constructor is explicitly, intentionally unavailable. – Eljay Dec 01 '17 at 18:42
  • OMFG. I had no idea *member variables* with special constructors could be constructed this way in a class. I have spent years unnecessarily creating pointers. I feel *so* dumb. – zzxyz Dec 01 '17 at 18:49
  • It seems to have been a cache problem in the development tool. After restart and cache cleanup it works as intended. – Max Kielland Dec 01 '17 at 19:51