C++ 中单参数构造函数的问题以及如何解决
在 C++ 中,如果一个类有一个可以用单个参数调用的构造函数,那么这个构造函数就成为一个转换构造函数,因为这样的构造函数允许自动转换为正在构造的类。
问题:
每当有一个带有单个参数的构造函数并且有一个函数接受相同类类型的参数,但是当使用与构造函数相同的参数类型调用该函数时,在这种情况下,该函数被成功调用。这是因为参数被构造函数隐式转换为类类型。参数被传递给构造函数,然后函数被执行。这是我们没有预料到的。
下面是演示上述问题的 C++ 程序:
C++
// C++ program to implement
// the above approach
#include
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);
}
C++
// C++ program to implement
// the above approach
#include
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);
}
C++
// C++ program to implement
// the above approach
#include
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);
}
C++
// C++ program to implement
// the above approach
#include
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;
}
C++
// C++ program to implement
// the above approach
#include
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;
}
C++
// C++ program to implement
// the above approach
#include
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;
}
C++
// C++ program to implement
// the above approach
#include
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;
}
Value of data is: 10
解释:
在上面的代码中,有一个用户定义的构造函数接受一个 GFG(类类型)类型的参数,还有一个函数也接受一个类类型的参数。当尝试通过传递 int 类型参数来调用函数时,在这种情况下,函数被成功调用。这是因为用户定义的构造函数。传递给函数的 int 值被隐式转换为类类型,并且数据成员使用传递的参数 (var) 的值进行初始化。
解决方案:
为了避免这个隐式转换的问题,就是让构造函数显式化。下面是演示隐式转换问题解决方案的 C++ 程序——
C++
// C++ program to implement
// the above approach
#include
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);
}
输出:
退税:
然而,这种方法有一些缺点。如果在同一个程序中用户真的想将 int 数据类型转换为 class 数据类型并将 int 值分配给该类的对象怎么办。以下分配将导致错误-
int var = 10;
GfG obj = var; // This will result in error
要解决这个问题,您可以将 var 显式转换为 GfG,然后将其分配给 obj。
GfG obj = (GfG) var; // This works fine
下面是实现上述方法的 C++ 程序——
C++
// C++ program to implement
// the above approach
#include
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);
}
Value of data is: 10
让我们再考虑一个例子,并讨论当显式也不起作用时会发生什么。
C++
// C++ program to implement
// the above approach
#include
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;
}
输出
String is:
解释:
在上面的示例中,用户尝试使用 char 值初始化字符串,但 char 是整数系列的一部分,因此编译将使用构造函数 GfG(int) 将 char 隐式转换为 GfG。这会产生意想不到的结果。
如上所述,解决此问题的方法之一是使用关键字explicit。
C++
// C++ program to implement
// the above approach
#include
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;
}
输出:
解释:
上面的程序将无法编译,因为 GfG(int) 是显式的,并且找不到合适的转换构造函数来将“x”隐式转换为 GfG。请注意,显式关键字只能禁止隐式转换,无法避免使用上面讨论的显式关键字进行类型转换。
删除关键字
上述问题的一种部分解决方案是创建一个私有构造函数 GfG(char)。下面是实现这个概念的 C++ 程序:
C++
// C++ program to implement
// the above approach
#include
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;
}
输出:
解释:
在上面的代码中, GfG(char) 构造函数是私有的。这阻止了从类外部访问构造函数,但它仍然可以在类内部使用。解决这个问题的方法是使用delete 关键字。
删除关键字:
下面是实现删除关键字概念的C++程序:
C++
// C++ program to implement
// the above approach
#include
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;
}
输出:
解释:
当一个函数被删除时,对该函数的任何使用都是编译时错误。