Qt/C++ 构造函数与explicit
1、默认构造函数
默认构造函数是指所有参数都提供了默认值的构造函数,通常指无参的构造函数或提供默认值的构造函数。如类Test1和Test2的构造函数
class Test1
{
public:
Test1(){} // default constructor
} ;
或
class Test2
{
public:
Test2(int i=){} // default constructor
} ;
如果你没有为你的类提供任何构造函数,那么编译器将自动为你生成一个默认的无参构造函数。一旦你为你的类定义了构造函数,哪怕只是一个,那么编译器将不再生成默认的构造函数。
2、何时需要为你的类提供默认构造函数
有很多情况,列举如下:
1. 当你使用静态分配的数组,而数组元素类型是某个类的对象时,就要调用默认的构造函数,比如下面的代码。
Object buffer[]; // call default constructor
2. 当你使用动态分配的数组,而数组元素类型是某个类的对象时,就要调用默认的构造函数,比如下面的代码,如果Object没有默认的构造函数,是无法通过编译的,因为new操作符要调用Object类的无参构造函数类初始化每个数组元素。
Object* buffer = new Object[];
3. 当你使用标准库的容器时,如果容器内的元素类型是某个类的对象时,那么这个类就需要默认的构造函数,原因同上。
vector<Object> buffer;
4. 一个类A以另外某个类B的对象为成员时,如果A提供了无参构造函数,而B未提供,那么A则无法使用自己的无参构造函数。下面的代码将导致编译错误。
class B
{
B(int i){}
}; class A
{
A(){}
B b;
}; int main(void)
{
A a(); // error C2512: 'B' : no appropriate default constructor available getchar() ;
return ;
}
再比如下面的代码,类A定义了拷贝构造函数,而没有提供默认的构造函数,B继承自A,所以B在初始化时要调用A的构造函数来初始化A,而A没有默认的构造函数,故产生编译错误。
class A
{
A(const A&){}
}; class B : public A
{ }; int main(void)
{
B b; //error C2512:'B': no appropriate default constructor available getchar() ;
return ;
}
除以上情况之外还有很多,不在此一一举例描述。
参考自:http://www.cnblogs.com/graphics/archive/2012/10/02/2710340.html
从Qt谈到C++(一):关键字explicit与隐式类型转换
提出疑问
当我们新建了一个Qt的widgets应用工程时。会自动生成一个框架,包含了几个文件。其中有个mainwindow.h的头文件。就是你要操纵的UI主界面了。我们看看其中的一段代码:
class MainWindow : public QMainWindow
{
Q_OBJECT//一个宏,暂不考虑 public:
explicit MainWindow(QWidget *parent = );
~MainWindow(); private:
Ui::MainWindow *ui;
};
这段代码定义了一个新的类MainWindow,继承自QMainWindow。我们可以看到在它的构造函数里,前面有一个关键字 explicit 。相信大家都对没有这个关键字的构造函数不陌生。那么这个 explicit 是起到什么作用的呢?
explicit研究
explicit是C++中的关键字,不是C语言中的。英文直译是“明确的”、“显式的”意思。出现这个关键字的原因,是在C++中有这样规定的基础上: 当定义了只有一个参数的构造函数时,同时也定义了一种隐式的类型转换。 先看类型转换。
类型转换
C/C++中,有很多类型转换。比如:
double a = 12.34;
int b = (int)a;
我们都知道这时b的值是12. 在变量前面加括号包裹的类型,就能实现显式的类型转换。这种叫做强制类型转换。顺便值得一提的是,C++中还支持这种强制类型转换的例子:
double a = 12.34;
int b = int(a);
除此之外,还有一种转换叫做 隐式类型转换。
double a = 12.34;
int b = a;
同样的,b的值也是12.虽然没有显式的转换类型,但是编译器会帮你自动转换。同样的,不仅是基本数据类型,自己定义的类和对象之间也存在这种转换关系。
隐式转换的场景
等于号与构造函数
比如你有一个类的对象A:
class A
{
public:
A(int i)
{
a = i;
}
int getValue()
{
return a;
};
private:
int a;
};
你会发现,你在main函数中,使用下面的语句时是合法的:
A a = ;
之所以类A的对象可以直接使用整型通过等于号来初始化,是因为这一语句调用了默认的单参数构造函数,其效果等价于 A temp(10); a(temp);
首先编译器执行A temp(10);在栈中创建了一个临时对象(假设叫做temp)。然后再调用对象a的拷贝初始化构造函数 a(temp) 给a初始化。然后临时对象temp销毁。这就是编译器做的隐式转换工作。你可以想到这样的隐式操作的结果和直接显示调用A a(10);的结果是一样的,但是隐式转换因为使用了拷贝构造函数所以在开销上会更高一些。当然这基本数据类型,或许不明显。如果一个复杂的对象,比如Qt的窗口。那么开销可想而知。
又如当你使用如下语句会不通过:
A a = "";
因为没有参数为字符串的单参数构造函数。知道了这个,你修改一下就能通过了。
class A
{
public:
A(int i)
{
a = i;
}
A(char * c)
{
a=c[];
}
int getValue()
{
return a;
};
private:
int a;
};
函数调用
我们再定义一个函数print 用来打印A对象的值。
void print(A a)
{
cout<<a.getValue();
};
在main函数中:
void main()
{
print();
}
这样是可以编译运行的。虽然我们并没有创建一个类A的对象来传给print 函数。但是编译器默认会调用类A的单参数构造函数,创建出一个类A的对象出来。
加上explicit
上面可以看出编译器会为你做一些,隐式的类型转换工作。这或许会让你感到方便,但是有时候却会带来麻烦。我们来做一个假设:
上面这个类A,只接受整型和字符串型。所以你想传递一个字符串 “2” 作为参数来构造一个新的对象。比如 A b = “2”; 然而,你却写错了,双引号写成了单引号变成了 A b = ‘2’; 然而这样并不会报错。编译器 会把 字符 ‘2’ 转型成 整型 也就是它的ascll码—— 50。为了避免这样我们不希望的隐式转换,我们可以加上explicit 关键字。
public:
explicit A(int i)
{
a=i;
}
这样就能避免隐式的类型转换了,当你误写成单引号的时候,就会报错。这样就只允许显示的调用单参数构造函数了。如 A a(10); A b("123");
不仅如此,在加上explicit之后,print函数也会报错了。因为编译器不会主动调用explicit标识的构造器。这就需要你自己显示的来调用了:
print(A());
当然了,是否应该禁止隐式转换是没有定论的,没有一种放之四海皆准的标准,具体看你的情景需要了。
一般而言,显示调用构造器,能避免一些麻烦,让程序员手动来管理。很多人说C++难,因为很多东西对于程序员来说不是透明的,比如内存释放什么的,这个显式调用也是需要程序员自己动手的。然而我感觉这正是C++的魅力所在,C++给了程序员几乎等同于上帝的权力,所有一切都能自己掌控,还比如运算符重载的权力,甚至像Qt这样可以自定义slot和signal关键字(其实是宏),这在其他高级语言里是不可想象的。当然了,语言这东西,是仁者见仁智者见智的。没必要争论优劣。我一直认为的是:没有最优秀的语言,只有最合适的语言。编程语言本身没有优劣之分,但是不同程序员对于不同语言确有好恶之别。
explicit使用注意事项:
* explicit 关键字只能用于类内部的构造函数声明上。
* explicit 关键字作用于单个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数),如Circle(int x, int y = 0) 。
* 在C++中,explicit关键字用来修饰类的构造函数,被修饰的构造函数的类,不能发生相应的隐式类型转换,只能以显示的方式进行类型转换。
顺便一提
explicit关键字只用在类内部的声明中。在外部的实现部分不需要使用。
#include<iostream>
using namespace std;
class A
{
public:
explicit A(int i);
A(char * c)
{
a=c[];
}
int getValue()
{
return a;
};
private:
int a;
};
A::A(int i)//无需再指明explicit
{
a=i;
}
void print(A a)
{
cout<<a.getValue();
};
void main()
{
print(A());
}
转自:http://blog.csdn.net/guodongxiaren/article/details/24455653?utm_source=tuicool&utm_medium=referral
Qt/C++ 构造函数与explicit的更多相关文章
- QT宏 Q_OBJECT,explicit, QHostAddress, quint, emit
QT相關 一. 參考: 1.宏Q_OBJECT 二. explicit struct constrcution 三. QHostAddress Detailed Description: The QH ...
- c++ 构造函数以及explicit 关键字的使用
关于构造函数中的隐式转换: 在一个类所定义的构造函数中,存在如下的用法: #pragma once #ifndef __EXERCISE__ #define __EXERCISE__ #include ...
- Qt ------ 初始化构造函数参数,parent
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWindow) { ui->setup ...
- QT在构造函数中退出程序
原地址:http://www.tuicool.com/articles/RZnYze 在QT的界面类的构造过程中,如果想退出整个程序,暴力的做法是调用exit(-1)进行,另外一种不是那么暴力的方式如 ...
- C++ explicit关键字,修饰构造函数,ctor
#include <iostream> // operator Type() 类型操作符重载 // operator int() // operator double() // ... / ...
- Qt入门实例
一.基于Qt设计师 1.创建一个GUI项目,选择“Qt4 Gui Application”.其中还有Empty Qt4 Project(空的工程),Qt4 Console Applicaiton(基于 ...
- C++中explicit关键字的使用
看书看到了explicit关键字,就来做个笔记,讲得比较明白,比较浅. 在C++中,我们有时可以将构造函数用作自动类型转换函数.但这种自动特性并非总是合乎要求的,有时会导致意外的类型转换,因此,C++ ...
- [转载]explicit关键字
本文转自http://www.programlife.net/cpp-explicit-keyword.html. 其实explicit主要用于防止隐式转换,用于修饰构造函数.复制构造函数[注意:一般 ...
- C++构造函数与析构函数
转自http://blog.csdn.net/tqtuuuu/article/details/6652144 构造函数 对于C++的构造函数,暂且将其分为以下几类: 1. 默认构造函数 2. 隐士转换 ...
随机推荐
- RHEL6 - 图形化设置IP
RHEL6下我们除了麻烦地修改网卡的主配置文件外,还可以通过setup,system-config-network等工具指令打开网卡的图形化界面 #setup #system-config-net ...
- 【驱动笔记11】使用DeviceIoControl通信
文章作者:grayfox作者主页:http://nokyo.blogbus.com原始出处:http://www.blogbus.com/nokyo-logs/34018521.html 在我昨日发布 ...
- gulp#4.0
gitbook教程: https://dragon8github.gitbooks.io/gulp-webpack/content/an-zhuang-gulp-4-0.html gulpfile.j ...
- MongoDB查询指定字段(field)返回指定字段的方法
使用MongoDB的时候需要只查询指定的字段进行返回,也就是类似mysql里面的 SELECT id,name,age 这样而不是SELECT *.在MongoDB里面映射(projection)声明 ...
- [QT] 小知识集锦
qt 中关于 QWidget 的背景颜色和背景图片的设置 首先设置autoFillBackground 属性为真 然后定义一个QPalette 对象 设置QPalette 对象的背景属性(颜色或图片) ...
- unity + win8.1 apps 小游戏demo
unity3d用的人挺多. . .本来想写个3d游戏试试. .额..貌似挺麻烦.. . .. ..先用unity写个简单的2d游戏吧.. (adsw回车 或者 触摸屏虚拟摇杆) 开发环境 unit ...
- tomcat在conf/Catalina/localhost目录下配置项目路径
转自:http://wangyl93-dl-cn.iteye.com/blog/1508517 在tomcat的conf/Catalina/localhost目录下配置项目路径,tomcat启动是会直 ...
- 基于epoll的简单的httpserver
该httpserver已经能够处理并发连接,支持多个client并发訪问,每一个连接能够持续读写数据.当然.这仅仅是一个简单的学习样例.还有非常多bug,发表出来仅仅是希望大家能够互相学习.我也在不断 ...
- SpringCloud重试机制配置
SpringCloud重试retry是一个很赞的功能,能够有效的处理单点故障的问题.主要功能是当请求一个服务的某个实例时,譬如你的User服务启动了2个,它们都在eureka里注册了,那么正常情况下当 ...
- js正则表达式判断一个字符串是否是正确的有数字和小数点组成的金钱形式和 判读数值类型的正则表达式
function checkRates(str){ var re = /^(([1-9][0-9]*\.[0-9][0-9]*)|([0]\.[0-9][0-9]*)|([1-9][0-9]*) ...