1

That is not a duplicate. Please read carefully. There are two variables x (of type int and X) and one member is actually declared private, which is used in a constructor. It is about understanding the constructor process in this very specific case.


I am doing a C++ course and I understand the following example that was given. It is about constructors.

#include <iostream>
using namespace std;

class Element {
    int value;
public:

    Element(int val) {
        value = val;
        cout << "Element(" << val << ") constructed!" << endl;
    }

    int Get(void) {
        return value;
    }

    void Put(int val) {
        value = val;
    }
};

class Collection {
    Element el1, el2;
public:

    Collection(void) : el2(2), el1(1) {
        cout << "Collection constructed!" << endl;
    }

    int Get(int elno) {
        return elno == 1 ? el1.Get() : el2.Get();
    }

    int Put(int elno, int val) {
        if (elno == 1) el1.Put(val);
        else el2.Put(val);
    }
};

int main(void) {
    Collection coll;
    return 0;
}

Then they mentioned the following

... We should also add that there is the following alternation for that case: when the constructor is divided between the declaration and the definition, the list of alternative constructors should be associated with the definition, not the declaration.

It means that the following snippet is correct:

class X {
public:
       X(int x) { };
};

class Y {
       X x;
public:
      Y(int x);
};

Y::Y(int x) : x(1) { };

Can someone explain? Is it really correct? And if yes, how to interpret that? Y has a one-parameter constructor, but no value is passed. x(1) is probably the constructor for the field X x in Y. Is the value of 1 (of x(1)) then passed to Y(int x) automatically although it is declared private in Y?

Community
  • 1
  • 1
Ely
  • 10,860
  • 4
  • 43
  • 64
  • I don't agree. That is not the same. Please read again. There are two variables x (of type int and X) and one member is actually declared private, which is used in a constructor. It is about understanding the constructor process in this very specific case. – Ely Jun 23 '15 at 17:22
  • 3
    Honestly I have no idea what you're asking. – Lightness Races in Orbit Jun 23 '15 at 17:26
  • The code snippet. Is it correct? If yes, why and how is the construction process? – Ely Jun 23 '15 at 17:27
  • Maybe he is asking about putting the constructor body in the class definition versus putting the constructor body in separate code outside the class definition. – Brian Walker Jun 23 '15 at 17:27
  • There are plenty of questions that already exist that explain the construction process. Please ask a specific question. As for whether the code is "correct", that entirely depends on what you intended for it to do. – Lightness Races in Orbit Jun 23 '15 at 17:28
  • The constructor for Y looks correct. The construction process doesn't change between putting the constructor body in the class definition versus putting it in separate code. – Brian Walker Jun 23 '15 at 17:29
  • It looks to me like your course material is using very confusing wording to say nothing other than "the _ctor-initialiser_ goes on the constructor _definition_ not the declaration, if the two are distinct in your program". And I have no idea what you think `private`ness has to do with it.... – Lightness Races in Orbit Jun 23 '15 at 17:29
  • 1
    What may be confusing you is that in `Y::Y(int x)` that "x" is never used. The ": x(1)" is using the member "x" defined in the class definition (X x;). – Brian Walker Jun 23 '15 at 17:31
  • Where does the x in Y(int x) come from? – Ely Jun 23 '15 at 17:31
  • From the person who is creating an instance of Y. `Y test1(1)` will pass x as 1 (though it is never used). What you might be wanting to say in the constructor is `Y::Y(int x) : x(x) { }` which will pass the integer value x to the constructor of the X object. – Brian Walker Jun 23 '15 at 17:35
  • 1
    @Elyasin that `x` is a bad choice for a method parameter. – crashmstr Jun 23 '15 at 17:35
  • 2
    I'm not sure I understand the question. Are you confused about out-of-class member function definitions? Modulo inline, the second one is equivalent to `class Y{ X x; public: Y(int z) : x(1) { } };` – T.C. Jun 23 '15 at 17:36
  • That was not my choice. That is from the course. By the way, the course is from the C++ institute. They claim the last code snippet is valid C++, but I don't understand it :-( – Ely Jun 23 '15 at 17:37
  • The `x` in `Y(int x)` is the name of the constructor's parameter. Whatever argument you pass to `Y` when constructing an instance can be referred to by the name `x`. The `x` in the `: x(1)` part refers to the data member named `x` that `Y` contains. I have no idea what this quoted section *We should also add ...* is talking about. – Praetorian Jun 23 '15 at 17:37
  • @T.C. So you mean it is another constructor of Y; some sort of a complement to make sure x can be instantiated ? Or does Y have two constructors? One of them should be erroneous because x has to have a parameter for the constructor, right? – Ely Jun 23 '15 at 17:39
  • 2
    @Elyasin there is only one constructor for `Y`. It is *declared* in the class body and *defined* later. The choice of `x` for the parameter name is a bad choice since it will hide the member `x` in the *body* of the constructor. – crashmstr Jun 23 '15 at 17:41
  • Thanks guys, I think I got it. Now I feel it was a stupid question, but for some reason I was thinking invocation/construction and not declaration. I'm happy with the answer. – Ely Jun 23 '15 at 17:44

1 Answers1

1

In the second code snippet, there is no construction actually going on—it's just a definition of the classes and constructors. The only "special" thing about it is that the body of Y's constructor is defined outside the class; it could be in a different file, for example. In this case, it's no different from putting the body directly into the class1:

class Y {
       X x;
public:
      Y(int x) : x(1) {}
};

When this constructor of Y is invoked, it constructs the member variable x by passing 1 to the X constructor taking int. The constructor of Y doesn't do anything else, i.e. it ignores its own parameter.

The syntax Y::Y used in the original code snippet is standard syntax for defining a member function outside of the class definition. For a non-constructor, it would look like this:

class Foo
{
  int bar() const;
};

int Foo::bar() const
{
  return 42;
}

1 With the slight difference that when put directly into the class definition, the function is implicitly inline (can be present in more than one translation unit).

Angew is no longer proud of SO
  • 167,307
  • 17
  • 350
  • 455