Qt构造函数的初始化问题

参考链接

  1. QT中用父类构造函数初始化子类的成员变量
  2. Qt ------ 初始化构造函数参数,parent
  3. C++ 构造函数和析构函数是否可以继承?

描述

在Qt新建继承Qt类的类后,经常会在构造函数看到parent的参数的初始化。如:
DialogRangeReference.h

class DialogRangeReference : public QDialog
{
    Q_OBJECT

public:
    explicit DialogRangeReference(QWidget *parent = 0);
    ……
private:
    Ui::DialogRangeReference *ui;
}

DialogRangerReference.cpp

DialogRangeReference::DialogRangeReference(QWidget *parent) :
    QDialog(parent),
    ui(new Ui::DialogRangeReference)
{
    ……
}

解析

以上面的代码为例,可以发现DialogRangeReferenceQDialog的子类。uiDialogRangeReference的成员。ui(new Ui::DialogRangeReference)是初始化ui,这里new出一个对象赋值给ui

而在构造函数定义中QDialog(parent)会比较晦涩。这里需要结合继承于QDialog来说,QDialogDialogRangeReference的父类,并且DialogRangerReference的构造函数带参数QWidget *parent,因此这里的其实是调用了父类的构造函数,并将参数parent传给了父类的构造函数。在执行DialogRangeReference的构造函数前,先调用父类QDialog的构造函数。由于这里是调用,而不是赋初值,因此这里的写法与ui是有区别的。

扩展

  1. 构造函数的参数为QWidget是因为QWidget为窗口类的基类;QObject则是非窗口类的基类;
  2. 指定parent可以指定此类的父类,当父类delete时,Qt可以保证所有子类都会被正确的delete掉,能够帮助开发人员管理一部分内存;
  3. 指定了parent则指定了组件的父组件。这对于一个对话框来说是比较合适的,因为对话框一般不作为顶层容器出现。因此任务栏上不会有对话框的位置。如果对话框不指定parent,则对话框会作为顶层容器出现。

补充示例

父类Student.h如下:

#include<iostream>
#include<string>

using namespace std;

class Student
{
public:
    Student(int n,string nam,char s) {
        num=n;
        name=nam;
        sex=s;
    }

    ~Student(){}

protected:
    int num;
    string name;
    char sex;
};

子类Student1.h如下:

class Student1:public Student
{
    Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s) {
    age=a;
    addr=ad;
    }

    void show(){}

private:
    int age;
    string addr;  
};

main.cpp如下:

int main()
{
    Student1 stud1(10010,"Wang",'f',19,"BeiJing Road,Shanghai");
    ......
}

解析

派生子类会继承基类的所有成员,除了构造函数和析构函数(派生子类会调用父类的无参数构造函数,是调用,而不是继承)。因此,子类从父类继承过来的成员变量,若不想自己写构造函数初始化时,就只能先初始化父类中的成员变量,然后再继承过来。

从上面代码中可以看出,子类Student1中的构造方法只有对新增成员int age和string addr的初始化操作,对于从父类继承过来的成员num,name,sex无初始化语句,但子类又不能继承父类的构造方法,要么就另外再写一个初始化语句,可这样操作就造成了重复性语句。此时就得通过Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s){age=a;addr=ad;}先初始化父类成员变量,从而间接初始化子类从父类继承过来的成员变量。


请注意派生子类构造函数首行的写法:

Student1(int n,string nam,char s,int a,string ad):Student(n,nam,s)

其一般形式为:

派生类构造函数名(总参数列表):基类构造函数名(参数列表)
{
    派生类中新增数据成员初始化语句;
}

冒号前面的部分是派生类构造函数的主干,它的总参数表列中包括基类构造函数所需的参数和对派生类新增的数据成员初始化所需的参数。冒号后面的部分是要调用的基类构造函数及其参数。

基类构造函数后面括号内的参数表列中只有参数但无参数类型,因为在这里不是定义基类构造函数,而是调用基类构造函数,因此这些参数是实参而不是形参。他们可以是常量、全局变量和派生类构造函数总参数表中的参数。


从上面代码可以看到,在main函数中,建立对象stud1时,有5个参数,其中前3个是用来传递基类构造函数的,后2个用来对派生子类所增加的数据成员初始化。

以上例子中,调用基类构造函数时的实参是从子类构造函数的总参数表中获得的,也可以不从那传递,直接使用常量或全局变量,如:Student1(string nam,char s,int a,string ad):Student(10010,nam,s);这样父类的n默认初始化为10010,子类直接把n=10010继承过来,因此不用写。

  • 6
    点赞
  • 21
    收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
©️2022 CSDN 皮肤主题:书香水墨 设计师:CSDN官方博客 返回首页
评论 2

打赏作者

Giant NG

你的鼓励将是我创作的最大动力

¥2 ¥4 ¥6 ¥10 ¥20
输入1-500的整数
余额支付 (余额:-- )
扫码支付
扫码支付:¥2
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、C币套餐、付费专栏及课程。

余额充值