I am trying to understand how default constructor (provided by the compiler if you do not write one) versus your own default constructor works.
So for example I wrote this simple class:
class A
{
private:
int x;
public:
A() { std::cout << "Default constructor called for A\n"; }
A(int x)
{
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main (int argc, char const *argv[])
{
A m;
A p(0);
A n();
return 0;
}
The output is :
Default constructor called for A
Argument constructor called for A
So for the last one there is another constructor called and my question is which one and which type does n have in this case?
A n();
declares a function, named n, that takes no arguments and returns an A.
Since it is a declaration, no code is invoked/executed (especially no constructor).
After that declaration, you might write something like
A myA = n();
This would compile. But it would not link! Because there is no definition of the function n.
A n();
could be parsed as an object definition with an empty initializer or a function declaration.
The language standard specifies that the ambiguity is always resolved in favour of the function declaration (§8.5.8).
So n is a function without arguments returning an A.
For the last one NO constructor gets called.
For that matter no code even gets generated. All you're doing is telling (declaring) the compiler that there's a function n which returns A and takes no argument.
No there is not a different constructor.
A n();
is treated as a declaration of function taking no arguments and returning A object. You can see this with this code:
class A
{
public:
int x;
public:
A(){ std::cout << "Default constructor called for A\n";}
A(int x){
std::cout << "Argument constructor called for A\n";
this->x = x;
}
};
int main(int argc, char const *argv[])
{
A m;
A p(0);
A n();
n.x =3;
return 0;
}
The error is:
main.cpp:129: error: request for member ‘x’ in ‘n’, which is of non-class type ‘A()’
Related
Is there a nice way to have a non static value as default argument in a function? I've seen some older responses to the same question which always end up in explicitly writing out the overload. Is this still necessary in C++17?
What I'd like to do is do something akin to
class C {
const int N; //Initialized in constructor
void foo(int x = this->N){
//do something
}
}
instead of having to write
class C {
const int N; //Initialized in constructor
void foo(){
foo(N);
}
void foo(int x){
//do something
}
}
which makes the purpose of the overload less obvious.
One relatively elegant way (in my opinion) would be to use std::optional to accept the argument, and if no argument was provided, use the default from the object:
class C {
const int N_; // Initialized in constructor
public:
C(int x) :N_(x) {}
void foo(std::optional<int> x = std::nullopt) {
std::cout << x.value_or(N_) << std::endl;
}
};
int main() {
C c(7);
c.foo();
c.foo(0);
}
You can find the full explanation of what works/doesn't work in section 11.3.6 of the standard. Subsection 9 describes member access (excerpt):
A non-static member shall not appear in a default argument unless it
appears as the id-expressionof a class member access expression
(8.5.1.5) or unless it is used to form a pointer to member
(8.5.2.1).[Example:The declaration of X::mem1()in the following example
is ill-formed because no object is supplied for the non-static
memberX::a used as an initializer.
int b;
class X {
int a;
int mem1(int i = a);// error: non-static memberaused as default argument
int mem2(int i = b);// OK; useX::b
static int b;
};
If I override a virtual method, can I change the name of an argument in the child? Same type of argument, just change say (int num) to (int n)?
Is this example valid?
class Animal
{
public:
virtual int foo(int num) {
return num + 1;
}
};
class Cat : public Animal
{
public:
int foo(int n) override {
return n - 1;
}
};
If it is, why do argument names not matter?
The name of the argument is irrelevant.
The only thing that must match is the type of the parameter.
And also whether the class method itself is const, or not. And the method's return value must match.
To give a proper answer, the names of the arguments do not matter because they are not part of function signature. See http://en.cppreference.com/w/cpp/language/function for (quite comprehensive) explanation.
By the way, const-ness of the argument itself is not part of the signature either. This way, void foo(const int x); and foo (int x) are equivalent.
I compiled the code with an additional:
int main() {
// your code goes here
Animal a;
Cat c;
cout << a.foo(4) << endl;
cout << c.foo(4) <<endl;
return 0;
}
This ran and gave the expected output of 5, 3.
So it seems changing argument names is perfectly valid.
You can as long as parameters are scoped to the function being declared to. What matters is the number of parameters and type so be sure that the overriden function has the same signature as the base's
class Animal
{
public:
virtual int foo(int) { // even no parameter identifier and it is ok
return 0;
}
};
class Cat : public Animal
{
public:
int foo(int n) {
return n - 1;
}
};
While using virtual method, all you need to do is to keep the declaration of the method same. That is, if I talk about your code you can change the variable number but not the datatype, parameter list, return type and function name.
Question:
Is there a difference between the following initializations?
(A) What exactly is the second one doing?
(B) Is one more efficient than the other?
int variable = 0;
int variable = int();
This question also applies to other data types such as std::string:
std::string variable = "";
std::string variable = std::string();
Background:
I basically got the idea here (the second code sample for the accepted answer) when I was trying to empty out a stringstream.
I also had to start using it when I began learning classes and realized that member variable initializations had to be done in the constructor, not just following its definition in the header. For example, initializing a vector:
// Header.h
class myClass
{
private:
std::vector<std::string> myVector;
};
// Source.cpp
myClass::myClass()
{
for (int i=0;i<5;i++)
{
myVector.push_back(std::string());
}
}
Any clarity on this will be greatly appreciated!
Edit
After reading again, I realized that you explicitely asked about the default constructor while I provided a lot of examples with a 1 parameter constructor.
For Visual Studio C++ compiler, the following code only executes the default constructor, but if the copy constructor is defined explicit, it still complains because the never called copy constructor can't be called this way.
#include <iostream>
class MyInt {
public:
MyInt() : _i(0) {
std::cout << "default" << std::endl;
}
MyInt(const MyInt& other) : _i(other._i) {
std::cout << "copy" << std::endl;
}
int _i;
};
int main() {
MyInt i = MyInt();
return i._i;
}
Original (typo fixed)
For int variables, there is no difference between the forms.
Custom classes with a 1 argument constructor also accept assignment initialization, unless the constructor is marked as explicit, then the constructor call Type varname(argument) is required and assignment produces a compiler error.
See below examples for the different variants
class MyInt1 {
public:
MyInt1(int i) : _i(i) { }
int _i;
};
class MyInt2 {
public:
explicit MyInt2(int i) : _i(i) { }
int _i;
};
class MyInt3 {
public:
explicit MyInt3(int i) : _i(i) { }
explicit MyInt3(const MyInt3& other) : _i(other._i) { }
int _i;
};
int main() {
MyInt1 i1_1(0); // int constructor called
MyInt1 i1_2 = 0; // int constructor called
MyInt2 i2_1(0); // int constructor called
MyInt2 i2_2 = 0; // int constructor explicit - ERROR!
MyInt2 i2_3 = MyInt2(0); // int constructor called
MyInt3 i3_1(0); // int constructor called
MyInt3 i3_2 = 0; // int constructor explicit - ERROR!
MyInt3 i3_3 = MyInt3(0); // int constructor called, copy constructor explicit - ERROR!
}
The main difference between something like:
int i = int(); and int i = 0;
is that using a default constructor such as int() or string(), etc., unless overloaded/overridden, will set the variable equal to NULL, while just about all other forms of instantiation and declarations of variables will require some form of value assignment and therefore will not be NULL but a specific value.
As far as my knowledge on efficiency, neither one is "better".
Scenario is I have a function which calls parameterized constructor when I want to initialize. So what I want to do is to call constructor of my choice when I want. But it works when I use A() to call default constructor but it does not work with a constructor with the parameter rather I am getting following error.
Error 1 error C2082: redefinition of formal parameter
'tmp' c:\users\adnan\documents\visual studio
2012\projects\project3\project3\source.cpp 12 1 Project3
class A
{
public:
int id;
void i(int tmp)
{
A(tmp);
}
A()
{
cout<<"default const"<<endl;
}
A(int id)
{
this->id = id;
}
};
int main()
{
A obj[2];
for(int i=0;i<2;i++)
{
obj[i].i(i*2);
}
cout<<"obj[0].id = "<<obj[0].id;
cout<<endl;
cout<<"obj[1].id = "<<obj[1].id;
cout<<endl;
system("pause");
return 0;
}
In your member function i you're trying to call the c'tor of A like this:
void i(int tmp)
{
A(tmp);
}
In fact A(tmp) declares a variable tmp of type A. Since tmp is already declared as int inside the same scope, the compiler complains.
If you want a variable of type A and initialize it via the A::A(int) c'tor then you need to give a name to that variable. E.g.:
A a(tmp);
The line
A(tmp);
doesn't call the constructor, it's declaring an instance of A called "tmp" - it's equivalent to
A tmp;
Since the formal parameter is called "tmp", that's a redefinition.
(Despite what you might expect, A tmp(); is not equivalent to A tmp;- look for "the most vexing parse" to learn more.)
The reason it "works" when you write
A();
is that it creates an anonymous instance (an entirely different one from this) which is immediately thrown away.
In other words, that code doesn't do what you thought it did.
There's no way (in C++03) to explicitly call a constructor except using "placement new", which should not be done unless you know what you're doing.
If you want to delay "initialization" of an object until after it's been constructed, use an initialization function:
class A
{
public:
int id;
void init(int tmp)
{
id = tmp;
}
A()
{
cout<<"default const"<<endl;
init(0); // Avoid accidental undefined behaviour.
}
A(int id)
{
init(id);
}
};
There is an ambiguity in the grammar involving expression-statements
and declarations:
I have cited the C++ Standard.
That is in this code snippet
void i(int tmp)
{
A(tmp);
}
A(tmp); is considered by the compiler as a declaration equivalent to
A tmp;
To distinguish the constructor call from the declaration you could write
void i(int tmp)
{
( A )( tmp );
}
In this case ( A )( tmp ) is a constructor call though there is no any sense in this statement.
I know that default constructors initialize objects to their default values, but how do we view these values? If there's a variable of type int, it is supposed to be initialized to 0. But how do we actually view these default values of the constructors? Can anyone please provide a code snippet to demonstrate the same?
Unless specified otherwise, objects are constructed with their default constructor, only if one is available.
And for example ints are not initialized.
This is a common source of huge troubles and bugs, because it can have any value.
So the rule is , always initialise your variables, and for a class you do it in the initialization list
class A
{
private:
int i;
float f;
char * pC;
MyObjectType myObject;
public:
A() : // the initialisation list is after the :
i(0),
f(2.5),
pC(NULL),
myObject("parameter_for_special_constructor")
{}
}
}
In C++, int is not a class and does not have a default (or any other) constructor.
An int is not guaranteed to be initialised to 0.
If you have a class that has an int as an attribute, you should explicitly initialise it in each of the class's constructors (not just the default one).
class sample
{
private:
int x;
public:
sample()
:x(0)
{
}
sample(const int n)
:x(n)
{
}
sample(const sample& other)
:x(other.x)
{
}
// [...]
};
This way you (and users of your class) can "view" the default values.
Good coding practice: write your own constructor, so you know how it will be initialized. This is portable and guaranteed to always have the same behaviour. Your code will be easier to read and the compiler knows how to make that efficient, especially when using the special notation:
class Foo
{
public:
Foo() : i(0), j(0) {}
private:
int i;
int j;
};
AFAIK, if T is a type (not necessarily a class), T() returns a default value for the type T. Here's a small test I ran:
int main()
{
char c = char();
int i = int();
cout << "c = " << hex << (int) c << endl;
cout << "i = " << i << endl;
}
The output is:
c = 0
i = 0
Default constructors do not automatically initialise ints to 0. You can use parentheses to indicate the default value though.
struct X
{
int x;
};
struct X x1; // x1.x is not necessarily 0
struct Y
{
int y;
Y() : y()
{
}
};
struct Y y1; // y1.y will be 0
show your code
And if your int value is a member of class .
you must give it a value in your default constructor func
The default constructor is which can be invoked with 0 parameters. For example
struct X
{
X(int x = 3) //default constructor
{
//...
}
};
It initializes the object to whichever state you code it to initialize. However, if you don't define any constructor at all the compiler will attempt to generate a default constructor for you - which, in turn is equivalent to a constructor with no arguments and no body. That means that all the members of class/struct type will be initialized with their def. ctors and all the members of primitive types like int will remain uninitialized. Please note that I specialy noted that the compiler will attempt to generate a dflt ctor, because it can fail to do so, for example when one or more members of the class do not have default constructors. HTH
AS soon as you have created an object start printing the values such as ob.x.
Thats the only way u can know what default constructor has assigned to the variables.