About constructor overload of a class template [duplicate] - c++

This question already has answers here:
What is this weird colon-member (" : ") syntax in the constructor?
(14 answers)
Closed 3 years ago.
now I am just really new to C++, currently I have a piece of code below:
#include <iostream>
using namespace std;
template<typename T>
class Test1
{
public:
Test1():var1(1) {
cout << "Constructor1" << endl;
}
Test1(T a):var1(a) {
cout << "Constructor2" << endl;
}
private:
int var1;
};
template<typename T>
class Test2
{
public:
Test2():var2(x) {
cout << "Constructor3" << endl;
};
private:
int x;
Test1<int> var2;
};
int main()
{
Test2<int> var3;
return 0;
}
The output will just be
Constructor2
Constructor3
I wonder why the constructor2 will be called instead of constructor1, since in the class Test2, when creating the object var2, I didn't pass in any parameters, shouldn't the constructor without parameter being called?
Thank you in advance!

The constructor for a variable is determined by its initialization. You have an initialization list on your Test2 constructor
Test2():var2(x) {
so you have to look there for how Test2::var2 is initialized. In the initialization list, you're passing the integer x (that's not initialized to anything), so it calls the Test1 constructor that takes an integer.
If you don't explicitly initialize var2 in your initializer list (for example, if you just assign to it in the constructor body), then it will be default initialized and say "constructor 1" instead of 2

Related

Create object of class B inside class A and pass a method of Class A in constructor of object of Class B [duplicate]

This question already has answers here:
How can I pass a member function where a free function is expected?
(9 answers)
Pass Member Function as Parameter to other Member Function (C++ 11 <function>) [duplicate]
(2 answers)
Passing a pointer to a class member function as a parameter
(2 answers)
Closed 24 days ago.
I am trying to create object of another class in one class (I am able to do this) and I want to pass a method of the first class to the second class as constructor argument (I am not able to do this. I get compiler errors). Below is the code.
#include <iostream>
using namespace std;
class B
{
public:
B(void (*fp)(void))
{
fp();
}
private:
};
class A
{
public:
void printHelloWorld()
{
cout << "Hello World!" << endl;
}
private:
B ObjB{printHelloWorld};
};
int main()
{
cout << "!!** Program Start **!!" << endl;
A ObjA;
cout << "!!** Program End **!!" << endl;
return 0;
}
I receive the following Errors.
main.cpp:21:27: error: could not convert ‘{((A*)this)->A::printHelloWorld}’ from ‘’ to ‘B’
21 | B ObjB{printHelloWorld};
| ^
| |
| <brace-enclosed initializer list>
The code can be compiled on this link also
https://onlinegdb.com/xB70hwQph
The code works fine if I make printHelloWorld as static function or Shift the defination of printHelloWorld outside the class.
I am looking for a solution for this simple looking problem.
You cannot use a non-static method as an argument for a C style function pointer parameter.
The reason is that in order to invoke it you need a this pointer which is not available with a C function pointer.
You can use std::function, together with a lambda capturing this to achieve what you need.
However - since you initialize your ObjB directly when it is declared, the complete A might not have been fully constructed yet (e.g. via a specific contructor) and therefore calling the method directly from B's constructor is problematic. In your trivial case it can work, but imagine the method printHelloWorld accessing some A members.
Instead I made B store the std::function so that it can later be invoked via the invokeF() method.
Code example:
#include <iostream>
#include <functional>
class B
{
public:
//----vvvvvvvvvvvvvvvvvvvvvvvvv----
B(std::function<void(void)> fp) { m_fp = fp; }
void invokeF() { m_fp(); }
private:
std::function<void(void)> m_fp;
};
class A
{
public:
void printHelloWorld() { std::cout << "Hello World!" << std::endl; }
void invokeBF() { ObjB.invokeF(); }
private:
//----------vvvvvvvvvvvvvvvvvvvvvvvvvvvvvv----
B ObjB{ [this]() { printHelloWorld(); } };
};
int main()
{
std::cout << "!!** Program Start **!!" << std::endl;
A ObjA;
ObjA.invokeBF();
std::cout << "!!** Program End **!!" << std::endl;
return 0;
}
Output:
!!** Program Start **!!
Hello World!
!!** Program End **!!
Demo (Godbolt)
A side note: Why is "using namespace std;" considered bad practice?.

why can i put variable name as constructor parameter in c++? [duplicate]

This question already has answers here:
Is it true that a default constructor is synthesized for every class that does not define one?
(6 answers)
Closed 3 months ago.
in following code:
`
#include <iostream>
struct MyStruct {
int i = 1;
};
int main() {
MyStruct(some); // some is actually a variable name, it compiles, is it in the
// c++ standard?
std::cout << some.i << std::endl;
}
`
why can i initialzie MyStruct(some)?
above code compiles and runs
I doubt that the variable "some" in the first code is a variable, it wouldn't run when I try to declare a variable called some.
But your problem with this code...
struct MyStruct {
MyStruct(const int &value) {}
};
int main() {
std::string(s2);
MyStruct(some); // illegal now
std::cout << s2 << std::endl;
}
is that you don't have an identifier for the MyStruct that you are instantiating.
struct MyStruct {
MyStruct(const int &value) {}
};
int main() {
int some = 5;
std::string(s2);
MyStruct myStruct (some); // illegal now
std::cout << s2 << std::endl;
}
Here I placed "myStruct" as the identifier for the "MyStruct". I also declared a variable called "some" to check if it runs that way, which it does.
The way of declaring and defining a variable is very wired. If you want to define std::string and MyStruct, you are supposed to use the following way: std::string s2("initialized value"); MyStruct some. In your second case, MyStruct has defined a constructor so the default constructor in the first case doesn't exist anymore unless you explicitly define it.
So in the second case, if you want to initialize an instance with one argument, the following is a supported way:MyStruct some(10);. This statements call the constructor you write.

Initialization of member variable via parentheses doesn't work [duplicate]

This question already has an answer here:
Why class data members can't be initialized by direct initialization syntax?
(1 answer)
Closed 11 months ago.
For the following codes, can anyone explain why we can't initialize the variable data by parentheses?
#include <iostream>
using namespace std;
class X
{
private:
int data(1); // wrong here
public:
void print()
{
cout << data << endl;
}
};
int main()
{
X temp;
temp.print();
return 0;
}
There isnt actually much to explain, its just not valid syntax. Default member initializers are
class X
{
private:
int data{1}; // ok
int data2 = 42; // also ok
public:
void print()
{
cout << data << endl;
}
};
While int data(1); is not valid syntax for a default member initializer. See here for details: https://en.cppreference.com/w/cpp/language/data_members

Does std::list variable in the class need initialization?

I have recently read something like this. I konw it is not so complex. But as a beginner, I just don't know why it works, so here is the description.
#include <list>
#include <iostream>
using namespace std;
template <typename T>
class A
{
public:
list<T *> testlist;
A();
~A();
void m_append(T* one);
};
template <typename T>
A<T>::A()
{
cout << "constructor" << endl;
}
template <typename T>
A<T>::~A()
{
cout << "destructor" << endl;
}
template <typename T>
void A<T>::m_append(T* one)
{
cout << *one << " push in" << endl;
testlist.push_back(one);
}
int main(void)
{
A<int> a;
int b = 4;
int c = 5;
int d = 6;
a.m_append(&b);
a.m_append(&c);
a.m_append(&d);
return 0;
}
In my opinion this testlist is not initialized, there should be something wrong.
But it works.
constructor
4 push in
4
5 push in
5
6 push in
6
destructor
So I am pretty confused. There is no need to initialize this testlist or?
Data member testlist is not mentioned in the member initializer list of constructor of A, and doesn't have default member initializer (since C++11), then it would be default initialized via the default constructor of std::list.
when a base class or a non-static data member is not mentioned in a constructor initializer list and that constructor is called.
And
There is no need to initialize this testlist or?
It depends on your intent. If the default initialization is enough, then yes.
To understand this, you must know how a list is constructed.
It has a control block on the stack and then allocates elements on the heap if you insert elements. The control block is initialized by the constructor.
Here is a picture to understand how this looks like:
So you don't need to initialize the list.

Is it valid to have a constructor call another constructor of the same class in its initialization list? [duplicate]

This question already has answers here:
Can I call a constructor from another constructor (do constructor chaining) in C++?
(15 answers)
Closed 5 years ago.
#include <iostream>
#include <string>
class Data
{
private:
int day, month, year;
public:
Data() : Data(0,0,0) {};
Data(int d, int m, int y) : day(d) , month(m), year(y) {}
void print() { std::cout << day << " " << month << " "<< year << std::endl; }
};
int main()
{
Data a;
a.print(); //ok - output: 0,0,0 and no compiler errors
}
A constructor does not have a returning value, and a constructor is called when an object is created, meaning the data can be initialized, so when I call a constructor from another constructor, is this completely valid?
I've also noticed that Data() { Data(0,0,0); }; does NOT initialize the current class data members.
Why is it that Data() : Data(0,0,0) {}; works and Data() { Data(0,0,0); }; does not?
It is perfect practice to do perform:
Data() : Data(0,0,0) {};
You are simply calling utilizing your initializer list.
The reason
Data() {
Data(0,0,0);
}
does no work is because all you have done is created an "anonymous" Data object on the stack within the Constructor which will be destructed as soon as the default constructor is completed.