I am trying to understand the order of exectution of a class which has nested objects of another class inside it. Here's my simple program :
#include<iostream>
#include <string>
using namespace std;
class Alpha
{
int a;
public:
Alpha(int x)
{
a=x;
}
};
class Beta
{ int b;
public:
Beta(int y)
{
b=y;
}
};
class Gamma
{
Alpha A;
Beta B;
int c;
public:
Gamma(int a,int b, int d): A(a), B(b)
{
c=d;
}
};
void main()
{
Gamma g(5,6,7);
}
As you can see, Gamma has 2 nested objects. Now when the first line of main() is executed, how does the execution start inside the class Gamma? The constructer is called first or the objects/data-members are created first?
The question of constructor execution order is simple: first, Gamma constructor starts, but then it immediately proceeds to initializing Alpha and Beta, as specified in your initialier list. Once the intializer list is done, the body of Gamma's constructor is executed.
There is an important twist to this: C++ will initialize nested objects in the order in which they are declared in the class, not in the order in which they are listed in the initializer list. In other words, Alpha will be initialized ahead of Beta even if you reverse A(a) and B(b):
// The compiler will issue a warning for this
Gamma(int a,int b, int d): B(b), A(a)
{
c=d;
}
The constructer is called first or the objects/data-members are created first?
From an initializer list the members or base class constructor calls are executed before the constructors body of the containing / inherited class.
You can easily check what's going on placing some output statements in the constructors
Alpha(int x) {
cout << "a = " << a << std::endl;
a=x;
cout << "Alpha(" << a << ")" << std::endl;
}
Beta(int y) {
cout << "b = " << b << std::endl;
b=y;
cout << "Beta(" << b << ")" << std::endl;
}
Gamma(int a,int b, int d): A(a), B(b) {
cout << "c = " << c << std::endl;
c=d;
cout << "Gamma(" << c << ")" << std::endl;
}
Output is
a = 0
Alpha(5)
b = 134514731
Beta(6)
c = -1218371596
Gamma(7)
See here for a fully working sample.
Objects in the initialization list are initialized first. Then, the body of the constructor inside {} is executed.
Related
This question already has an answer here:
C++ constructor not called
(1 answer)
Closed 4 years ago.
In my code below, I wanted to test what would happen if I had an object, that contained another object whose constructor throws exception. But the code below does absolutely nothing. Nothing is printed on the console at all.
class A
{
public:
A()
{
cout << "in A constructor" << endl;
throw "error creating A";
}
~A()
{
cout << "destructing A" << endl;
}
};
class C
{
public:
C()
{
cout <<"in C constructor" << endl;
}
~C()
{
cout << "in C destructor " << endl;
}
};
class B
{
public:
C c;
A a;
B(A a_, C c_): a(a_), c(c_){}
B(){}
};
int main()
{
try{
B b(A, C);
//B b;
}
catch(char const* s)
{
cout <<"catching" << endl;
}
}
If in the try block, I use commented code instead, then it shows fine.
I also tried doing
B b(A(), C());
Still nothing.
This is a function declaration with return type B, name b, and two unnamed arguments of type A and C:
B b(A, C);
The same for
B b(A(), C());
as names can be enclosed by parentheses (to allow grouping, necessary when working with e.g. function pointers etc.), and even names that are left out can be enclosed by parentheses. You can turn it into a variable b of type B by
B b(A{}, C{});
One of the motivation for the curly braces to initialize variables was to disambiguate in such cases. Here, it obviously comes in handy.
class A
{
public:
A(int a, int b, int c)
:x(a), y(b), z(c)
{}
void display()
{
cout << "x is " << x << endl;
cout << "y is " << y << endl;
cout << "z is " << z << endl;
}
int x;
protected:
int y;
private:
int z;
};
class B : public A
{
public:
B(int x, int y, int z, int extra)
: A(x, y, z), num(extra)
{}
void display()
{
cout << "x is " << x << endl;
cout << "y is " << y << endl;
//cout << "z is " << z << endl;
}
private:
int num;
};
int main()
{
A yo1(1,2,3,);
B yo2(4,5,6,100); //<---
yo2.display(); //I want to print 1 2 3 100
return 0;
}
I have a simply inheritance here. Using inheritance, I want to get A's values and put it into B. How do I access the values of its data members from class A by created a B object? I created an object of class A and gave them the value 1,2,3. In the end, I want to print 1 2 3 100 by using class B's display function.
I understand how I can use the variables from class A but can I also grab their values?
you are confused with concept of inheritance,
B yo2(4,5,6,100);
during this there is separate copy of base class created for the object yo2 which has nothing to do with the object yo1
A yo1(1,2,3,);
the data members x,y,z will have 1,2,3 for yo1 and 4,5,6 for yo2
if you want the output to be
1 2 3 100
then create the object as :
B yo2(1,2,3,100);
you can modify your derived class as
class B : public A
{
public:
B(A& obj, int extra)
: A(obj.x, obj.y, obj.z), num(extra)
{}
void display()
{
A::display();
cout << "num is " << num << endl;
}
private:
int num;
};
and in main you can access as
int main()
{
A obj(1,2,3);
B objB(obj,100);
objB.display();
}
I think you might have misunderstood inheritance.
There is no way for yo2 to know about the values you have given to yo1.
The values yo2 have in A's variables are 4,5,6 respectively.
to illustrate inheritance a little you could rename the display methods "display_a" and "display_b" and then you could access them thus:
yo1.display_a(); // OK. prints values 1,2,3
yo1.display_b(); // Compile error.
yo2.display_a(); // OK. prints values 4,5,6
yo2.display_b(); // OK. prints values 4,5 from variables inherited from A.
To get what happens with the two "display" methods in your original code, look up overloading and the key-word "virtual". Also look up the operator ::
I hope this helps.
First, I think you have misunderstood what inheritance means and yo1 has nothing to do with yo2 at all. Second, you want to use B display function to display A object's members but you are lazy to construct B with argument 1,2,3 because A has constructed using those. Because A's y is protected and A's z is private, you must use a way to copy A object's members to B object if you want achieve your goal. So I think the rajenpandit's answer is right and useful for you.
This question already has an answer here:
Most vexing parse
(1 answer)
Closed 9 years ago.
class A {
public:
A() { cout << "A()" << endl; }
};
class B {
public:
A a;
B(const A& a1) : a(a1) { cout << "B(const A&)" << endl; }
/* B(const A& a1) { a = a1; cout << "B(const A&)" << endl; } */
};
int main() {
B b(A()); /* no ouput */
}
No output is generated for the above code. Is that due to the compiler optimization (copy elision) as discussed in this link?
But if I have a B class constructor and re-write the code like below:
class A {
public:
A() { cout << "A()" << endl; }
};
class B {
public:
A a;
B() {}
B(const A& a1) : a(a1) { cout << "B(const A&)" << endl; }
/* B(const A& a1) { a = a1; cout << "B(const A&)" << endl; } */
};
int main() {
B().a; // gives output A()
}
add an extra pair of parentheses:
B b((A()));
// you can also fix it using new C++11 initialization syntax:
B b{A()};
the problem you are facing it called most vexing parse, and it means compiler is not able to decide whether you want a function declaration or variable definition.
[edit]
I should also add that standard requires compiler in such case to choose function declaration.
[edit]
clang is actually more helpfull in this case, and gives hint to use partentheses:
http://rextester.com/PECQ53431
source_file.cpp:16:8: warning: parentheses were disambiguated as a function declaration [-Wvexing-parse]
B b(A()); /* no ouput */
^~~~~
source_file.cpp:16:9: note: add a pair of parentheses to declare a variable
B b(A()); /* no ouput */
^
( )
1 warning generated.
B b(A());
Is ambiguous and may be interpreted either as a variable declaration or as a declaration of a function that returns a restult of type B and takes a single unnamed parameter of type a function with no parameters and returns a result of type A. Although you may think first one should take place the standard dictates in fact the second one will happen. See the article about most vexing parse in wikipedia.
Instead of creating A object after B object creation, create first As object in main.
A a;
B b(a);
Here's a program, where I am trying to call the class constructor multi::multi(int, int), in the function void multi::multiply(). The output is
30
30
instead of expected
30
25
Why?
#include <iostream.h>
class multi{
private:
int a;
int b;
public:
multi(int m, int n){
a = m;
b = n;
}
void multiply(){
cout << "\n\n" << a*b;
multi (5, 5);
cout << "\n" << a*b;
}
};
main(){
multi x(5,6);
x.multiply();
return 0;
}
multi (5, 5);
It creates a temporary object, and gets destroyed by the end of the full expression. It doesn't do multiplication or printing.
To see the desired output, you can add a reset() member function to your class:
class multi{
private:
int a;
int b;
public:
multi(int m, int n) : a(m), b(n) {} //rewrote it
void reset(int m, int n) { a = m; b = n; } //added by me
void multiply(){
cout << "\n\n" << a*b;
reset(5, 5); //<-------------- note this
cout << "\n" << a*b;
}
};
By the way, prefer using member-initialization-list when defining constructors.
When you're calling the constructor multi(5, 5) you're actually creating a temporary object that is immediately destructed.
This doesn't work, because multi(5, 5); creates a temporary object of class multi, which is immediately destroyed, because it is not used for anything
Since multiply() is a member function of class multi, it has access to the private members, so it can just set a and b directly. You can get your expected output by rewriting multiply like this:
void multiply()
{
cout << "\n\n" << a*b;
b = 5;
cout << "\n" << a*b;
}
You can't call constructors like this. What your code does is create a new temporary instance of multi, which gets discarded immediately.
Once an object is constructed, you can't call its constructor again. Create an assign() function or something similar in your class.
You can't call a constructor of an already created object. What you are doing in code is, creating a temporary object.
Compiler will report error if you do try to do
this->multi(5,5).
For example, in this piece of code, if line [a] is commented out, the output is 0.
inh2.cpp
#include<iostream>
using namespace std;
class A {
public:
int x;
A() { x = 10; }
};
class B : public A {
public:
int x; // <--------- [a]
B() { x = 0; }
};
int main() {
A* ab = new B;
cout << ab->x << endl;
}
results from gcc
$ g++ inh2.cpp
$ ./a.out
10
$
I have two questions:
How does ab->x resolve to 10 in the above case? The object is of type class B, and thus should value to 0.
Why does commenting Line [a] change the behaviour of the code? My reasoning is that x would have anyways been inherited, which should result in same behaviour.
My reasoning for Q #1 above:
ab points to the memory location of an object of class B. It is a physical object in the sense that all the variables with their values are assigned memory.
Variable x within this object stores value 0.
When ab->x is done, ab tells us the memory location of the object, and we go look inside it to find that x is 0. So we should print 0.
Where am I wrong here?
Yes, it is of type B, but you are assigning it as a pointer to an A, and therefore it is using the x defined on A (as when we're dealing with a pointer to A, we don't know that B even exists, even though that's what you allocated).
When you comment out the line, during the construction phase, As constructor is called first, then Bs constructor, which sets x (in its base class) to 0. There is only one x at this point, and Bs constructor is called last.
Making a some small modifications:
#include <iostream>
using namespace std;
class A {
public:
int x;
A()
:x(10)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
virtual ~A() {}
};
class B : public A {
public:
int x; // <--------- [a]
B()
:A()
,x(0)
{
std::cout << __FUNCTION__ << std::endl;
std::cout << x << std::endl;
}
};
int main() {
A* ab = new B;
cout << "ab->x: " << ab->x << endl;
cout << "ab->A::x " << ab->A::x << endl;
B* b = dynamic_cast<B*>(ab);
cout << "b->x: " << b->x << endl;
cout << "b->A::x " << b->A::x << endl;
cout << "b->B::x " << b->B::x << endl;
}
This gives you:
A
10
B
0
ab->x: 10
ab->A::x 10
b->x: 0
b->A::x 10
b->B::x 0
This demonstrates that:
ab->x refers to A::x because ab is of type A* and there is no such thing as a virtual variable. If you want polymorphism, you'll have to write a virtual int get_x() const method.
B::x hides A::x. This is a bad idea and should be avoided. Consider using a more meaningful name for your member variables and establish whether you can reuse the base class's variable before introducing a new one.
Casting to a B* allows you access to B's members as well as A's. This should be self-explanatory.