Problem with Single Argument Constructor in C++ and How to solve it
Last Updated :
25 Feb, 2022
In C++, if a class has a constructor which can be called with a single argument, then this constructor becomes a conversion constructor because such a constructor allows automatic conversion to the class being constructed.
Problem:
Whenever there is a constructor with a single argument and there is a function that takes an argument of the same class type but when this function is called using an argument type same as that of the constructor, in that case, the function gets called successfully. This is because the argument is implicitly converted to the class type by the constructor. The argument gets passed to the constructor and then the function gets executed. This is something we would not expect.
Below is the C++ program that demonstrates the above problem:
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
int data;
public:
// Constructor with single parameter
GfG(int a)
: data(a)
{
}
// Default constructor
GfG() {}
// Defining function to print
// the value of data member
void display()
{
cout << "Value of data is: " << data;
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
int var = 10;
// Function gets called even if
// int type argument is passed
func(var);
}
OutputValue of data is: 10
Explanation:
In the above code, there is a user-defined constructor that takes an argument of type GFG (class type) and there is a function that also takes an argument of class type. When there is an attempt to invoke the function by passing int type parameter, in this case, the function is called successfully. This happens because of the user-defined constructor. The int value passed to the function is implicitly converted to class type and the data member gets initialized with the value of the passed parameter (var).
Solution:
In order to avoid this problem of implicit conversion is to make the constructor explicit. Below is the C++ program to demonstrate the solution to the implicit conversion problem-
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
int data;
public:
// Constructor with single parameter
// declared explicit
explicit GfG(int a)
: data(a)
{
}
// Default constructor
GfG() {}
// Function to print value
// of data member
void display()
{
cout << "Value of data is: " << data;
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
int var = 10;
// This function call results
// in error
func(var);
}
Output:
Drawback:
This approach, however, has some drawbacks. What if in the same program the user really wants to convert int data type to class data type and assign an int value to an object of the class. The following assignment will result in an error-
int var = 10;
GfG obj = var; // This will result in error
To solve this problem you can explicitly convert var to GfG and then assign it to obj.
GfG obj = (GfG) var; // This works fine
Below is the C++ program to implement the above approach-
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
int data;
public:
// Constructor with single parameter
// declared explicit
explicit GfG(int a)
: data(a)
{
}
// Default constructor
GfG() {}
// Function to print value
// of data member
void display()
{
cout << "Value of data is: " << data;
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
int var = 10;
// Explicitly converting var to
// class (GfG) type
GfG obj = (GfG)var;
// Calling function with the
// converted variable obj
func(obj);
}
OutputValue of data is: 10
Let's consider one more example and discuss what happens when explicit will also not work.
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
private:
string str;
public:
// Constructor with single parameter
// declared explicit
GfG(int a)
{
str.resize(a);
}
// Default constructor
GfG(const char* string)
{
str = string;
}
// Function to print value
// of data member
void display()
{
cout << "String is: " << str << "\n";
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
// This line will compile and
// will use GFG(int)
GfG obj = 'x';
// Calling function with the
// converted variable obj
func(obj);
return 0;
}
Output
String is:
Explanation:
In the above example, the user is trying to initialize a string with a char value but char is a part of the integer family, so the compile will use the constructor GfG(int) to implicitly convert char to GfG. This will produce unexpected results.
As discussed above one of the solutions to this problem is to use the keyword explicit.
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
private:
string str;
public:
// Constructor with single parameter
// declared explicit
explicit GfG(int a)
{
str.resize(a);
}
// Default constructor
GfG(const char* string)
{
str = string;
}
// Function to print value
// of data member
void display()
{
cout << "String is: " << str << "\n";
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
// Compile-time error since
// GfG(int) is explicit, so
// nothing will match.
GfG obj = 'x';
// Calling function with the
// converted variable obj
func(obj);
return 0;
}
Output:
Explanation:
The above program will not compile, since GfG(int) was made explicit, and an appropriate converting constructor could not be found to implicitly convert 'x' to GfG. Please note that explicit keywords can only disallow implicit conversions, typecasting cannot be avoided using the explicit keyword as discussed above.
The delete keyword
One partial solution to the above problem is to create a private constructor GfG(char). Below is the C++ program to implement this concept:
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
private:
string str;
// Objects of type char cannot
// be constructed from outside
// the class
GfG(char)
{
}
public:
// Constructor with single parameter
// declared explicit
explicit GfG(int a)
{
str.resize(a);
}
// Default constructor
GfG(const char* string)
{
str = string;
}
// Function to print value
// of data member
void display()
{
cout << "String is: " << str << "\n";
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
// Compile-time error since
// GfG(char) is private
GfG obj = 'x';
// Calling function with the
// converted variable obj
func(obj);
return 0;
}
Output:
Explanation:
In the above code, GfG(char) constructor is made private. This has prevented access to the constructor from outside the class but it can still be used inside the class. The solution to this problem is to use the delete keyword.
Delete Keyword:
Below is the C++ program to implement the concept of delete keyword:
C++
// C++ program to implement
// the above approach
#include <iostream>
using namespace std;
// Defining the class
class GfG {
private:
string str;
// Any use of this constructor
// is an error
GfG(char) = delete;
public:
// Constructor with single parameter
// declared explicit
explicit GfG(int a)
{
str.resize(a);
}
// Default constructor
GfG(const char* string)
{
str = string;
}
// Function to print value
// of data member
void display()
{
cout << "String is: " << str << "\n";
}
};
// User-defined function that takes
// object of class GfG as argument
void func(GfG o)
{
o.display();
}
// Driver code
int main()
{
// Compile-time error since
// GfG(char) is deleted
GfG obj = 'x';
// Calling function with the
// converted variable obj
func(obj);
return 0;
}
Output:
Explanation:
When a function is deleted, any use of that function is a compile-time error.
Similar Reads
How to Retrieve Command-Line Arguments in C++?
Command-line arguments are the values or parameters that are passed after the name of the program through the command line or terminal when the program is executed. In this article, we will learn how to retrieve command-line arguments in C++. Retrieving Command Line Arguments in C++To access all the
2 min read
How to Parse Command Line Arguments in C++?
In C++, command line arguments are parameters that are passed to a program when it is invoked via command line or terminal. In this article, we will learn how to parse command line arguments in C++. Parse Command Line Arguments in C++In C++, we can parse the command-line arguments using the argc and
2 min read
How to Define a Move Constructor in C++?
In C++, we have a move constructor which is a part of C++11 move semantics and is used to handle resources for temporary and rvalue objects. In this article, we will learn how to write a move constructor in C++. How to Write Move Constructor in C++?The move constructor is defined similarly to a copy
2 min read
How to Use Initializer Lists in Constructors in C++?
In C++, the initializer list in constructors can be used to initialize member variables with a list of values. In this article, we will learn how to use initializer lists in the constructor in C++. Initializer List in Constructor in C++We can use initializer_lists in constructors for initializing th
2 min read
How to Use Default Arguments in Function Overloading in C++?
In C++, we can provide the default values for the input arguments into the functions and it is also supported in function overloading. In this article, we will learn how to use default arguments in function overloading in C++. Default Arguments in Function Overloading in C++We can define the default
2 min read
How to Resolve a Name Conflict in C++?
In C++, naming conflict occurs when two identifiers in the same scope have the same name and the compiler cannot infer which identifier to refer to when it is mentioned in the program. In this article, we will discuss what are name conflicts, what are its causes, and how to resolve the name conflict
4 min read
How to Create a Pointer to a Function in C++?
In C++, a function pointer is a variable that stores the address of a function that can later be called through that function pointer. It is useful for passing functions as parameters to other functions(callback functions) or storing them in data structures. In this article, we will learn how to use
2 min read
How to Write Getter and Setter Methods in C++?
In C++, classes provide a way to define custom data types that can encapsulate data and methods related to that data. Getter and setter methods are commonly used to access and modify private member variables of the class allowing for the controlled access and modification of data. In this article, w
2 min read
How to Implement a Copy Constructor in a Derived Class in C++
In object-oriented programming, a copy constructor is a special member function that initializes a new object as a copy of an existing object. In this article, we will learn how to implement a copy constructor in a derived class. Implementing Copy Constructor in a Derived Class in C++ In C++, when w
3 min read
How to Create a Class with Private and Public Members in C++?
In C++, the classes are blueprints for creating objects with specific properties and methods that provide a feature of access specifiers to the user through which they can control the access of the data members present in a class. In this article, we will learn how to create a class with private and
3 min read