Is it ok to use base class attribute in the initialization list? - c++

I have a class which has an attribute whose value depends on an attribute from its base class. This base class attribute is modified in the constructor so that I need its value after being modified. I tried to summarize the idea in this example:
#include <string>
#include <iostream>
class A
{
public:
int att_a;
A(int x) : att_a(x) {
att_a++;
}; // att_a is being modified in the constructor of A
};
class B : public A
{
public:
std::string att_b; // att_b is from a different type than att_a but its value is obtained from att_a
B(int y) : A(y), att_b(std::to_string(att_a)) {};
};
int main(int argc, char const *argv[])
{
B b = B(3);
std::cout << b.att_b << std::endl;
return 0;
}
I'm using attribute att_a from class A, which was modified during it's construction, as an input to a function that initializes att_b of class B. My concerns are:
Is that a good way of accomplishing what I want?
Even though it compiles and run, can it cause undefined behavior under certain circumstances?

Can it cause undefined behaviour?
No.
When using a member initialization list, the order is fully defined: First base-classes in their order, then members in their order. So at the time you create any member, all base classes and all previous declared members are instantiated. If you switch the order in your constructor, your compiler should output a warning.
Is it a good way of accomplishing what you want?
Since you don't tell us what you are going to do with those classes, i can't tell you if its a good way, but you can do it this way if it fits your needs.

Related

Pass private parent class type as parameter (C2247)

I have a quite niche problem concerning private inheritance. I also have a solution for the problem, but I don't understand why it works.
TL;DR
Why does private inheritance on some intermediate level prevent me from passing the base type as a parameter to a (privately) derived class?
Consider the following code (also available here http://cpp.sh/3p5zv5): I have a composite-type class that can contain pointers to child elements of its own type. Also, that class contains the template method MyMethodTemplate(T value), allowing any type of Parameter. I need to inherit from this class multiple times, such that MyMethodTemplate(T) is not available, and instead only a typed version MyMethod() can be called with e.g. int, string, whatever.
Since the derived classes were going to contain a lot of boilerplate code (not shown here), I wrote the class template cSpecializedComposite that inherits privately from cComposite (successfully hiding MyMethodTemplate()). Its method MyMethod() internally calls MyMethodTemplate() from its parent class. So far, so good.
Now, to get rid of the template parameter in my end user code, I wanted to write trivial classes that publicly inherit from the template (cSpecializedCompositeInt, cSpecializedCompositeString, ...). My assumption was that cSpecializedCompositeInt would know cSpecializedComposite's interface, but not its internals. In cSpecializedCompositeInt's constructor, I can optionally pass a vector of unique_ptr that is passed on to its parent constructor (who does god knows what with it, nothing to see here, move along). Note that the class definition for cComposite is visible to cSpecializedCompositeInt, even if cSpecializedCompositeInt doesn't inherit from it, as far as it knows.
However, I get a compiler error C2247 in cSpecializedCompositeInt's constructor, telling me I can't use cComposite, because cSpecializedComposite inherited privately from it. This occured on both msvc10 and GCC 4.9.2 (the compiler behind http://cpp.sh).
Changing the private inheritance to protected allows cSpecializedCompositeInt to know it inherited indirectly from cComposite, and the compiler error goes away.
In how far is this related to Private Inheritance and Derived Object to Base reference ?
#include <vector>
#include <memory>
class cComposite
{
public:
cComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: m_vecC(std::move(vecC))
{
//empty
}
template <typename T>
void MyTemplateMethod(T value)
{
//do something with any type of value
}
private:
std::vector<std::unique_ptr<cComposite>> m_vecC;
};
template <typename MySpecialType>
class cSpecializedComposite : private cComposite
{
public:
cSpecializedComposite(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cComposite(std::move(vecC))
{
//empty
}
void MyMethod(MySpecialType value)
{
//allow only MySpecialType as Input, call base class template method to do something
cComposite::MyTemplateMethod(value);
}
};
class cSpecializedCompositeInt : public cSpecializedComposite<int>
{
public:
cSpecializedCompositeInt(std::vector<std::unique_ptr<cComposite>>&& vecC)
: cSpecializedComposite(std::move(vecC))
{
//empty
}
};
int main(int argc, char* argv[])
{
std::vector<std::unique_ptr<cComposite>> vecC;
cSpecializedCompositeInt spec(std::move(vecC));
spec.MyMethod(5);
return 0;
}
One of the recurring themes on this site is requesting a Minimal, Complete, and Verifiable example. You did do a good job with the "complete" and "verifiable" parts, but not so much with the "minimal". Please allow me to simplify your code to remove potentially distracting details.
// Base class, constructed from a type that involves itself.
class A {
public:
A(A *) {}
};
// Intermediate class, derives privately from the base class.
class B : private A {
public:
B(A * a) : A(a) {}
};
// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
C(A * a) : B(a) {} /// error: 'class A A::A' is inaccessible
};
int main(int argc, char* argv[])
{
return 0;
}
Note the lack of templates and vectors; those are just red herrings. Also, apologies for using raw pointers; they are just a convenient way to introduce the issue with minimal overhead/baggage. (I'd use references, but that would turn one of the constructors into a copy constructor, which feels unwise.)
Look at the definition of B's constructor. In that definition, "A" is used twice: once as part of the type of the parameter, and once in the initializer list. For the latter case, the use of A definitely refers to the (private) base class of the class being constructed. Question: why should the compiler assume that the former case does not also refer to the private base class? (If the private base class was changed, would the parameter's type necessarily change as well? The compiler assumes "yes", but you could introduce another intermediate class, between A and B, which presumably would preserve the parameter's type.)
As far as I know (I have not double-checked the language specs), when you are in the context of B, any mention of its private base class is considered private information. You could think of the constructor's declaration as: B(<private> * a). Since C is not allowed to know the private information of B, it is not allowed to call this constructor. It simply cannot match the parameter list, much the same as if the parameter's type was defined within a private section of B. Fortunately, this can be circumvented by removing a mention of "A" from the parameter list.
In the following, the only change is the introduction and use of a typedef.
class A;
typedef A * special_type;
// Base class, constructed from a type that *indirectly* involves itself.
class A {
public:
A(special_type) {}
};
// Intermediate class, derives privately from the base class.
class B : private A {
public:
B(special_type a) : A(a) {}
};
// Most derived class, same constructor parameter as the base class.
class C : public B {
public:
C(special_type a) : B(a) {} /// no error!
};
int main(int argc, char* argv[])
{
return 0;
}
In your case, this would have the side benefit of introducing a shorter synonym for that rather symbol-rich std::vector<std::unique_ptr<cComposite>>.

Why did the creator of C++ decide to use constructor initializer list to initialize base classes?

Why did the creator of C++ decide to use constructor initializer list to initialize base classes? Why didn't he instead choose to use syntax like the second comment line in the following code?
class A{
public:
A() { }
};
class B : A{
public:
B() : A() { } // Why decide to use this one, using constructor initializer, to initialize base class?
B() { A(); } // Why not choose this one? It's easy for me to understand if it was possible.
};
int main(int argc, char *argv[]){
/* do nothing */
}
The advantage of using an initializer list is, that you have a completely initialized object in the body of the constructor.
class A {
public:
A(const int val) : val(val) { }
private:
const int val;
};
class B : A{
public:
B() : A(123) {
// here A and B are already initialized
}
};
So you have a guarantee that all members, even those of the parent, are not in an undefined state.
Edit
In the example of the question it is not necessary to call the base class in the initializer list, this is done automatically. So I slightly modified the example.
I can see a few possible alternatives to the current C++ rule that base classes and data members of a class type are initialised in the mem-initialiser list of the class type's constructor(s). They all come with their set of issues, which I will discuss below.
But first, note that you cannot simply write a derived constructor like this:
struct Derived : Base
{
Derived()
{
Base(42);
}
};
and expect the line Base(42); to call the base class constructor. Everywhere else in C++, such a statement creates a temporary object of type Base initialised with 42. Changing its meaning inside a constructor (or just inside its first line?) would be a syntax nightmare.
Which means that new syntax would need to be introduced for this. In the rest of this answer, I will use a hypothetical construct __super<Base> for this.
Now on to discuss possible approaches which would be closer to your desired syntax, and present their problems.
Variant A
Base classes are initialised in the constructor body, while data members are still initialised in the mem-initialiser list. (This follows the letter of your question the closest).
The would have the immediate problem of stuff executing in different order than it's written. For very good reasons, the rule in C++ is that base class subobjects are initialised before any data members of the derived class. Imagine this use case:
struct Base
{
int m;
Base(int a) : m(a) {}
};
struct Derived
{
int x;
Derived() :
x(42)
{
__super<Base>(x);
}
};
Written like this, you could easily assume x would be initialised first and then Base would be initialised with 42. However, that would not be the case and instead reading x would be undefined.
Variant B
Mem-initialiser lists are removed altogether, base classes are initialised using __super, and data members are simply assigned in the constructor body (pretty much the way Java does it).
This cannot work in C++ because initialisation and assignment are fundamentally different concepts. There are types where the two operations do vastly different things (e.g. references), and types which are not assignable at all (e.g. std::mutex).
How would this approach deal with a situtation like this?
struct Base
{
int m;
Base(int a) : { m = a; }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x); // This one's OK
r = *pd; // PROBLEM
}
};
Consider the line marked // PROBLEM. Either it means what it normally does in C++ (in which case it assigns a double into a "random place" which the uninitialised reference r references), or we change its semantics in constructors (or just in initial parts of a constructor?) to do initialisation instead of assignment. The former gives us a buggy program while the latter introduces totally chaotic syntax and unreadable code.
Variant C
Like B above, but introduce special syntax for initialising a data member in the constructor body (like we did with __super). Something like __init_mem:
struct Base
{
int m;
Base(int a) : { __init_mem(m, a); }
};
struct Derived : Base
{
double &r;
Derived(int x, double *pd)
{
__super<Base>(x);
__init_mem(r, *pd);
}
};
Now, the question is, what have we achieved? Previously, we had the mem-initialiser list, a special syntax to initialise bases and members. It had the advantage that it made clear these things happen first, before the constructor body starts. Now, we have a special syntax to initialise bases and members, and we need to force the programmer to put it at the start of the constructor.
Note that Java can get away with not having a mem-initialiser list for several reasons which don't apply to C++:
The syntax for creating an object is always new Type(args) in Java, whereas Type(args) can be used in C++ to construct objects by value.
Java only uses pointers, where initialisation and assignment are equivalent. For many C++ types, there operations are distinct.
Java classes can only have one base class, so using just super is enough. C++ would need to differentiate which base class you're referring to.
B() : A() { }
This will initialize the base class in user defined way.
B() { A(); }
This will NOT initialize the base class in user defined way.
This will create an object inside of constructor i.e B(){}
I think first initialization has better readability compared to the second and you can also deduce class hierarchy.

C++ constructor and passing variables to another class

Well, just new in classes and trying to create a simple program, that has 2 classes. Class A and Class B. Well I'm trying to initialize my variable in constructor in class A, and then make some action and pass it to class B, where I'm also can make some action. So class A is a base class. However, when I compile the program I got two mistake -
error: ā€˜iā€™ was not declared in this scope
For class A and class B. So I have two question 1) why constructor doesn't declare variables (according to the books constructor called first)? 2) what ways I can transfer the variable from class A to use in class B?
#include <iostream>
#include <cstdio>
using namespace std;
class A {
public:
A(){
int i =1;
}
~A(){}
int foo () {
int p = i+1;
i++;
return p;
}
};
class B : public A {
public:
int showme() {
return i;
}
};
int main() {
A j;
B k;
cout<< k.showme()<<endl;
cout<< j.foo()<<endl;
return 0;
}
First off, get a good book:
The Definitive C++ Book Guide and List
and familiarize yourself with the basics. Your question indicates there is a complete mess right now in your understanding of C++.
Now on to the actual Q's.
1) C-tor does not declare a class member variable, it can only declare a local variable since a c-tor is also a function. You need to declare the member variable explicitly like so:
class A {
int i;
public:
A(int _i): i(_i) { }
};
2) The term "transfer" is incorrect per se. In this case, the two classes are in an inheritance hierarchy, so the variable i is inherited by class B and if you declare it as protected, then it will be accessible in the way you do it. The function B::showme() is defined correctly. Fix the first part and the example is going to work.
3) Do not confuse classes and objects. When there is an object of class A declared, it is in no way related to another object of class A or B. j and k share their own private instances of int i (provided that you fix (a)) and if you want to have k's instance of i to be equal to that of j, you can e.g. implement a copy constructor or a pair of getter/setter functions.

Changing initialization order in constructor

class a
{
public:
a() : b(5), a1(10) //will firstly initialize a1 then b, so order here doesn't matter
int a1;
private:
int b;
}
The question is how to change the order (to have b initialized before a1)? I must have public members above private so that solution isn't okay for me. Of course here I use ints, the problem is more complex but it's just an example which shows what is my problem.
You cannot change the order of initialization, that is always defined by the order of declaration of the members in your class. This is necessary because the order of destruction must be the inverse of the order of construction, and if you changed the order of construction, the compiler would be forced to keep track of which order you have initialized your members in in order to generate proper destruction sequences.
So my advice is:
Just live with it, and;
Do not depend on the order of construction of your member variables.
To achieve point 2), you can provide default constructors for your members to do default initialization, and then initialize your members properly in the order you want inside the body of your constructor (in other words, decouple construction from logical initialization).
The order of initialization is determined by the order of declaration of the member variables. So if you want b to be initialized before a, you have to declare it before.
class a
{
public:
a() : b(5), a1(10) {}
private:
int b;
public:
int a1;
};
If I understand you correct you have some kind of style guide saying that public members should be before private.
In that case I would suggest you declare all your member variables private and create accessor functions to them instead. That way you get around it.
class a
{
public:
a() : _a1(5), _b(10)
int a1() const { return _a1; }
void a1(int value) { _a1 = value; }
int b() const { return _b; }
void b(int value) { _b = value; }
private:
int _a1;
int _b;
}
any sane compiler will anyway optimize it so the overhead will be minimal.
Make your b object private, declared it before a1, and make an accessor function for accessing the content of b. [If necessary, make it return a reference to the b object, so the calling code can modify it - although that is quite clearly bad design to expose the internals of a class to the calling code, whether it's through a public declaration or through returning a reference]

Does calling a C++ constructor from another member function/constructor execute the initializer list?

In a C++ object, when you call a constructor from another constructor or member function (after the object has already been constructed), does the initializer list of the constructor you're calling still get executed?
In C++11 you can have a constructor delegate work to another constructor in the same class, e.g.1:
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() : SomeType(42) {}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
In this instance it is forbidden to have an initaliser list after this delegation, e.g. changing the previous example to:
SomeType() : SomeType(42), number(0) {}
is an error.
If the question was "given an inheritance relationship does the initaliser list still get called?" the answer is yes, e.g.
#include <iostream>
struct SomeBase {
SomeBase(int) {}
};
struct SomeType : SomeBase {
int number;
SomeType(int new_number=0) : SomeBase(new_number), number(new_number) {}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
This is fine and works exactly how you'd hope.
It's not legal to directly call a constructor from within another constructor and in C++ prior to C++11 there's no constructor delegation allowed either, so something like:
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() {
SomeType::SomeType(0); // Error!
}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
Is an error and can't be expressed directly.
The following (which I'd guess is what you had in mind when writing the question) example isn't an error however, but doesn't do what you might hope:
#include <iostream>
struct SomeType {
int number;
SomeType(int new_number) : number(new_number) {}
SomeType() {
SomeType(0);
number = 42;
}
};
int main() {
SomeType a;
std::cout << a.number << std::endl;
}
Here the constructor with no parameters constructs an anonymous temporary instance of SomeType. It's a totally separate instance to the one that the constructor was called for initially. This is perfectly legal, but probably not what you meant to do. If you do this there's a risk that you might create infinite recursion if you're not careful and I think it's probably a good indicator of a design problem if you end up doing something like that!
1 Derived from the Wikipedia C++11 article
I assume you are referring to calling a base-class constructor from WITHIN the initialization list of a derived class. Assuming this is the case, then the BASE class constructor is executed first (including its initializer list), and THEN the derived class's initializer list is called.
In case you're wondering - the base class constructor is ALWAYS called prior to the initializer list being executed for a derived class, EVEN if the call to the base class constructor appears explicitly in the middle or end of the derived class's initializater list (as well as if it appears at the beginning). The reason is that the items in the initializer list are executed in the order they appear in the class DECLARATION in the class's header file, not in the order they appear in the initializer list in the constructor definition. And, the base class constructor is never declared in the derived class declaration. C++ requires that the base class constructor is ALWAYS called before the derived class constructor - whether the call to the base class constructor appears explicitly in the derived class's initializer list, or not - and no matter where it appears in the initializer list.
Don't call the constructor explicitly from another method, or another constructor.
Use two-stage initialization instead if you really need in, in which you call an Init() type method after constructing the object.
You cannot call a constructor explicitly, only by object construction either via new or on the stack. There are ways to hack it (e.g. placement new) but don't do that, just use two stage construction & initialisation.