C++ 中的显式构造函数
C++ 中的显式构造函数。
引言
构造函数确实让您的类变得简单优雅。构造函数是您的代码的基本基础,编译器会默认提供它。这称为默认构造函数。也就是说,在 C++ 中,如果您只写一行代码
Class A{ };
编译器会为您提供一个默认的零参数构造函数,以及一个析构函数、一个复制构造函数和一个复制赋值运算符。
背景
那么,什么是显式构造函数?
为了理解显式构造,我们需要先理解隐式转换,让我们看看它在编写代码时如何帮助您,以及有时这种特性为何不受欢迎。
使用代码
示例 1:考虑以下传统的、简单的复数类
#include <iostream> using std::cout; using std::endl; class complexNumbers { double real, img; public: complexNumbers() : real(0), img(0) { } complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; } complexNumbers( double r, double i = 0.0) { real = r; img = i; } friend void display(complexNumbers cx); }; void display(complexNumbers cx){ cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl; } int main() { complexNumbers one(1); complexNumbers five = 5; display(one); display(five); return 0; }
complexNumbers
类非常简单;它包含两个部分,名为 real
和 img
,分别表示复数的实部和虚部。代码定义了一个默认构造函数、一个复制构造函数,以及最重要的,定义了另一个构造函数,它帮助我们进行隐式构造。
在 main
中,我们首先创建一个名为“one
”的类对象,然后创建另一个名为“five
”的对象,这两个调用都成功,因为发生了隐式转换。因此,对于对象“one
”,对象的“real
”部分变为 1,“img”部分变为 0,对于对象“five
”,对象的“real
”部分变为 5,而“img
”部分变为 0。然后,我们使用名为“display
”的方法打印该复数。的确是个不错的例子,就目前而言,隐式转换很棒。下面是输出
Real Part: 1 Imag Part: 0
Real Part: 5 Imag Part: 0
现在,考虑这个
#include <iostream> using std::cout; using std::endl; class complexNumbers { double real, img; public: complexNumbers() : real(0), img(0) { } complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; } complexNumbers( double r, double i = 0.0) { real = r; img = i; } friend void display(complexNumbers cx); }; void display(complexNumbers cx){ cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl; } int main() { complexNumbers one(1); display(one); display(300); return 0; }
一个类似的例子,只是在 main
中添加了一行 ===> display(300);
。在这里,输出变为
Real Part: 1 Imag Part: 0
Real Part: 300 Imag Part: 0
砰!!!这真的出乎意料。首先,代码本身就令人困惑,display(300)
是什么意思?300 本身永远不是方法 display
期望作为参数的 complexNumbers
类的对象/实例。那么,这是怎么发生的?
由于方法 display
期望 complexNumbers
类的对象/实例作为参数,当我们传递十进制值 300 时,会发生隐式转换,进而将十进制值 300 转换为 complexNumbers
类的临时对象(从而将值 300 分配给该临时对象的实部)。
我们如何克服这种情况??
简单,强制编译器仅使用显式构造创建对象,如下所示
#include <iostream> using std::cout; using std::endl; class complexNumbers { double real, img; public: complexNumbers() : real(0), img(0) { } complexNumbers(const complexNumbers& c) { real = c.real; img = c.img; } explicit complexNumbers( double r, double i = 0.0) { real = r; img = i; } friend void display(complexNumbers cx); }; void display(complexNumbers cx){ cout<<"Real Part: "<<cx.real<<" Imag Part: "<<cx.img<<endl; } int main() { complexNumbers one(1); display(one); complexNumbers two =2; display(200); return 0; }
考虑以下语句
explicit complexNumbers( double r, double i = 0.0) { real = r; img = i; }
在这里,我们强制编译器不要对这段代码进行隐式转换。现在,如果程序员放入包含隐式转换的行,编译器会返回一个错误
bash-3.2$ g++ -g -o hello test2.cpp
test2.cpp: In function ‘int main()’:
test2.cpp:22: error: conversion from ‘int’ to non-scalar type ‘complexNumbers’ requested
test2.cpp:23: error: conversion from ‘int’ to non-scalar type ‘complexNumbers’ requested
从现在开始,程序员需要使用这个
display(complexNumbers(200)); //only explicit conversion is allowed…………