1、通过C++课本复习5.3节(类的静态成员)通过在Qt环境新建non-Qt项目实现这些章节中的代码。
#include <iostream> using namespace std; class Point { public: Point(int x=0,int y=0):x(x),y(y) { count++; } Point(Point &p){ x=p.x; y=p.y; count++; } ~Point(){ count--; } int getX(){ return x; } int getY(){ return y; } static void showCount(){ cout<<"Object count="<<count<<endl; } private: int x,y; static int count; }; int Point::count=0; int main(int argc, char *argv[]) { Point a(4,5); cout<<"Point A:"<<a.getX()<<","<<a.getY(); Point::showCount(); Point b(a); cout<<"Point B:"<<b.getX()<<","<<b.getY(); Point::showCount(); return 0; }
2、explicit关键字的用法。
(1)explicit关键字的用法和语法用途。
关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生。声明为explicit的构造函数不能在隐式转换中使用。
C++中, 一个参数的构造函数(或者除了第一个参数外其余参数都有默认值的多参构造函数), 承担了两个角色。1 是个构造器2 是个默认且隐含的类型转换操作符。
所以, 有时候在我们写下如 AAA = XXX, 这样的代码, 且恰好XXX的类型正好是AAA单参数构造器的参数类型, 这时候编译器就自动调用这个构造器, 创建一个AAA的对象。
这样看起来好象很酷, 很方便。 但在某些情况下(见下面权威的例子), 却违背了我们(程序员)的本意。 这时候就要在这个构造器前面加上explicit修饰, 指定这个构造器只能被明确的调用,使用, 不能作为类型转换操作符被隐含的使用。 呵呵, 看来还是光明正大些比较好。
explicit构造函数的作用
解析:
explicit构造函数是用来防止隐式转换的。请看下面的代码:
class Test1 { public: Test1(int n) { num = n; } //普通构造函数 private: int num; }; class Test2 { public: explicit Test2(int n) { num = n; } //explicit(显式)构造函数 private: int num; }; int main() { Test1 t1 = 12; //隐式调用其构造函数, 成功 Test2 t2 = 12; //编译错误,不能隐式调用其构造函数 Test2 t3(12); //显示调用成功 return 0; }
Test1的构造函数带一个int型的参数,代码19行会隐式转换成调用Test1的这个构造函数。而Test2的构造函数被声明为explicit(显式),这表示不能通过隐式转换来调用这个构造函数,因此代码20行会出现编译错误。
普通构造函数能够被隐式调用。而explicit构造函数只能被显示调用。
(2)为什么C++语言中要有explicit关键字,即它在编程应用中的意义。
C++ explicit关键字用来修饰类的构造函数,表明该构造函数是显式的,既然有"显式"那么必然就有"隐式",那么什么是显示而什么又是隐式的呢?
如果c++类的构造函数有一个参数,那么在编译的时候就会有一个缺省的转换操作:将该构造函数对应数据类型的数据转换为该类对象,如下面所示:
代码如下:
class MyClass { public: MyClass(int num) { number=num; } private: int number; }; //. MyClass obj=10; //ok, convert int to MyClass
在上面的代码中编译器自动将整型转换为MyClass类对象,实际上等同于下面的操作:
代码如下:
MyClass temp(10); MyClass obj = temp;
上面的所有的C++ explicit关键字相关的操作即是所谓的"隐式转换"。
如果要避免这种自动转换的功能,我们就要使用关键字explicit了,该关键字将类的构造函数声明为"显式",也就是在声明构造函数的时候前面添加上explicit即可,这样就可以防止这种自动的转换操作,
(3)为什么java语言可以没有这个关键字。
自动类型转换,也称隐式类型转换,是指不需要书写代码,由系统自动完成的类型转换。由于实际开发中这样的类型转换很多,所以Java语言在设计时,没有为该操作设计语法,而是由JVM自动完成。
转换规则
从存储范围小的类型到存储范围大的类型。
具体规则为:
byte→short(char)→int→long→float→double
也就是说byte类型的变量可以自动转换为short类型,示例代码:
byte b = 10;
short sh = b;
这里在赋值时,JVM首先将b的值转换为short类型,然后再赋值给sh。在类型转换时可以跳跃。示例代码:
byte b1 = 100; int n = b1;
注意问题在整数之间进行类型转换时,数值不发生改变,而将整数类型,特别是比较大的整数类型转换成小数类型时,由于存储方式不同,有可能存在数据精度的损失。强制类型转换,也称显式类型转换,是指必须书写代码才能完成的类型转换。该类类型转换很可能存在精度的损失,所以必须书写相应的代码,并且能够忍受该种损失时才进行该类型的转换。
3、完成课本3.1节实验,试验5种不同的窗口类型和窗口标志组合。然后:按住Ctrl键,点击“QWidget”,查看Qt源码,注意到枚举的应用,归纳enum关键字的用法,写示例代码运行。
#include "mainwindow.h" #include<QtWidgets> #include <QApplication> int main(int argc, char *argv[]) { QApplication a(argc, argv); QWidget *widget = new QWidget(0,Qt::Dialog); widget->setWindowTitle(QObject::tr("i am widget")); QLabel *lable = new QLabel(0,Qt::SplashScreen); lable->setWindowTitle(QObject::tr("lable:i am window")); lable->resize(180,20); QLabel *lable2 = new QLabel(widget); lable2->setText(QObject::tr("lable2: i am not individual window,only a widget's subcomponent")); lable2->resize(250,20); lable->show(); widget->show(); int ret = a.exec(); delete lable; delete widget; return ret; } QWidget *widget = new QWidget(0,Qt::Dialog); QLabel *lable = new QLabel(0,Qt::SplashScreen); 将上面两行代码改为下面代码即产生无边框窗口: QWidget *widget = new QWidget(0,Qt::Dialog|Qt:FramelessWindowHint); QLabel *lable = new QLabel(0,Qt::SplashScreen|Qt:WindowStayOnTopHint);