class phone {
public:
phone(int x) { num = x; }
int number(void) { return num; }
void number(int x) { num = x; }
private:
int num;
};
int main(void)
{
phone p1(10);
p1 = 20; // here!
return 0;
}
Hi, guys
Just I declared a simple class like above one.
After that I assigned int value to the object that class, then it worked!
(I printed its value. It was stored properly)
If there is not a construct with int parameter, a compile error occurred.
So, I think it's related with a constructor. Is that right?
Please give me a good explanation.
Thanks.
This is legal because C++ interprets any constructor that can be called with a single argument of type T as a means of implicitly converting from Ts to the custom object type. In your case, the code
p1 = 20;
is interpreted as
p1.operator= (20);
Which is, in turn, interpreted as
p1.operator= (phone(20));
This behavior is really weird, and it's almost certainly not what you wanted. To disable it, you can mark the constructor explicit to disable the implicit conversion:
class phone {
public:
explicit phone(int x) { num = x; }
int number(void) { return num; }
void number(int x) { num = x; }
private:
int num;
};
Now, the constructor won't be considered when doing implicit conversions, and the above code will cause an error.
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;
};
I'm new to C++ and I'm trying to understand how Class works. I made a simple example for myself when I encounter this problem. My class has one private property num and I'm trying to initialize it with an int this way: Number one = Number::ONE; but it doesn't work. However, when I do this it works fine: Number one; one = Number::ONE. I prefer the first option. Please help!
Here is my complete code:
class Number {
public:
enum {ONE, TWO, THREE, FOUR};
Number();
void print() const;
Number& operator=(int);
private:
int num;
};
Number& Number::operator=(int n) {
num = n;
return *this;
}
int main(int argc, const char * argv[]) {
Number n = Number::ONE; // doesn't work :(
n.print();
return 0;
}
Number::Number() {
num = 0;
}
void Number::print() const {
cout << num << endl;
}
In C++, when you write
Number one = Number::ONE;
the compiler will not use the assignment operator to initialize one. The operator= function is only invoked when you have an existing object that you want to reassign a new value. Instead, in this case, the compiler tries to invoke a conversion constructor, a constructor that takes in an object of the type on the right-hand side of the equality. Since you haven't defined a constructor like that, you're getting a compiler error.
One way to do this would be something like this:
class Number {
public:
Number(int value); // <-- Conversion constructor
...
};
Number::Number(int value) {
num = value;
}
Now, the code you've given here will compile properly.
You may want to do some reading into copy constructors, assignment operators, conversion constructors, and conversion assignment operators, since they're one of the trickier parts of routine C++ and often trip up people transitioning from basic C++ to more intermediate-level language techniques.
you didn't overload the constructor to take an integer as parameter that is why you get the error:
class Number
{
public:
enum {ONE, TWO, THREE, FOUR};
Number(int x) : num(x){}
void print() const;
Number& operator=(int);
private:
int num;
};
Probably a dumb question, I want to be able to use the passed in A & B values through the default constructor and use them in my functions like get(), but every time i do it gives the value of 0, how do i set the values of A & B and then be able to use them in my other functions. I know i could just pass the value into the get function from the main but i dont want to do it that way.
I have this in the .h,
class example
{
private:
int A, B;
public:
example();
example(int, int);
int get(int, int);
};
then in the .cpp
example::example()
{
cout << hello;
}
example::example(int x, int y)
{
A = x;
B = y;
}
int example::get(int c, int d)
{
int k = c + d / A;
return k;
}
And in the main()
int c = 10;
int d = 12;
int x = 2;
int y = 1;
example obj1(x, y);
example obj2;
int k = obj2.get(c, d);
cout << k;
Im thinking i should see an answer of 10 + 12 / 2 however its 10 + 12 / 0, not sure where i am going wrong if anyone could help thanks!
example(x, y);
does not do anything. It creates a temporary object that goes immediately out of scope. Then
example obj1;
should not compile, as you don't have a default constructor. If it compiles it means that you have provided a default constructor, which is invoked (and which probably doesn't do any initialization). However in your case you want to invoke the constructor example::example(int, int). The correct way of doing it is to define
example obj1(x, y);
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".
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?
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).