0

In the code below, class B has a member that is of type class A (varA1). I want to create a class B object where the member varA1 is intended to use the non-default constructor A(int v1) in class A.

#include <iostream>
using std::cout; using std::endl; using std::string;

class A {
public:
    A() { cout << "A default constructor" << endl;}
    A(int v1);
private:
    int var1;
};
A::A(int v1) {
    cout << "A int constructor" << endl;
    var1 = v1;
}

class B {
public:
    B() { cout << "B default constructor" << endl;}
    B(int v1);
private:
    int var1;
    A varA1;
};
B::B(int v1) {
    cout << "B int constructor" << endl;
    var1 = v1;
    A varA1(int v1);
}

int main()
{
    A TestA(1);
    B TestB(1);

    return 0;
}

However when I run the code above I get the following output:

A int constructor
A default constructor
B int constructor

I must be doing some wrong here. What do I need to change so that the B class uses the non-default constructor A(int v1) in class A?

I am using ubuntu 14.04LTS. Both GNU G++ 4.9 and 5.1 gave the same results.

Thanks in advance for reading and answering.

3 Answers3

4

Use a member initialization list:

B::B(int v1) : var1(v1), varA1(v1) {
    cout << "B int constructor" << endl;
}

Note that members are initialized (constructed) in the same order that they're declared in the class, so switching orders in the member initialization list won't change the order in which construction happens (and hopefully your compiler will warn you of this). This little detail becomes important if you try to construct varA1 from var1 and var1 is declared after varA1 in the class definition.


And by the way, all this line does (inside the B::B(int v1) constructor):

A varA1(int v1);

is forward declare a function named varA1 that takes an int parameter and returns an A object. This is semi-similar to the most vexing parse, though this isn't really a case of the most vexing parse.

Cornstalks
  • 37,137
  • 18
  • 79
  • 144
  • This works. Is member initialization list the only way to accomplish this? Thanks for the extra information! – user3569894 Oct 31 '15 at 21:09
  • @user3569894: Pretty much. C++11 added more convenient [member initialization](http://stackoverflow.com/questions/13662441/c11-allows-in-class-initialization-of-non-static-and-non-const-members-what-c), and also added [aggregate initialization](http://en.cppreference.com/w/cpp/language/aggregate_initialization). Those new features are useful, but they don't let you avoid using a member initialization list in this situation. – Cornstalks Oct 31 '15 at 21:17
  • Thank you again for the quick reply and thanks to Jameson as well. – user3569894 Oct 31 '15 at 21:33
1

You could use an initializer list in your B::B(int) constructor:

B::B(int v1) : varA1(v1) {
    cout << "B int constructor" << endl;
    var1 = v1; 
}
Jameson
  • 6,400
  • 6
  • 32
  • 53
0

If you do not want a default ctor, you might use

A(void) = delete;  

But recognize that you can temporarily add this declaration as a diagnostic measure to get the compiler to inform you for which code it wants to use the default ctor.

By replacing

A() { std::cout << "A default constructor" << std::endl;}

with

A() = delete;

The compiler will complain about the use of deleted function 'A::A()' in the body of B::B(int v1).

Thus, a brief inspection identifies that the second data attribute of B, i.e. "B::varA1", uses the default ctor of A (now deleted).

You also might consider 'fixing' the B ctor to NOT use the default ctor of A by explicitly invoking "varA1 (0)" in the initializer list of B ctor.

2785528
  • 5,438
  • 2
  • 18
  • 20
  • 1
    I think using the C-style syntax of `A(void)` is a little weird. But overall I think you make a good point about deleting constructors that aren't intended to be used. – Cornstalks Oct 31 '15 at 22:49
  • @Cornstalks - From [ The C++ Standard, 8.3.5/2: If the parameter-declaration-clause is empty, the function takes no arguments. The parameter list (void) is equivalent to the empty parameter list. ] This is from 2009 answer in SO, and is what I was taught (umm, some time ago). I consider it explicit ( i.e. it shows to readers of my code that I intentionally wanted no parameters, and did not simply overlook the issue ). I don't consider it C-style ... but I admit I know minimal C. – 2785528 Oct 31 '15 at 23:50
  • 1
    I know it's valid C++. But it was [inherited from C](http://stackoverflow.com/q/51032/1287251), which is why I'm pointing it out. In C++, `A()` shows quite clearly the function takes no parameters (and it's intuitive: there are no parameters listed, thus it takes no parameters) (and it's clearly intentional: if you wanted any parameters, you'd get a compiler error if you tried to pass or use any). You have a valid personal preference, but I wanted to add a note about it since the OP is (clearly) new to C++ and I wanted to help them avoid picking up C habits unnecessarily. – Cornstalks Nov 01 '15 at 00:09