//在 mainwindow.h 中
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
private:
Ui::MainWindow *ui;
int a;
}
// 解读这段构造函数
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
, ui(new Ui::MainWindow) // ui = =new Ui::MainWindow ;
, a(99) // a = 99;
{
....
// 首先 a(99) // a = 99; 就是等效于 a = 99 , ui(new Ui::MainWindow) 同理ui = =new Ui::MainWindow ;
// QMainWindow(parent) 这句话什么意思
}
// 举个例子,两个class, 一个 Animal ,一个Dog,Dog继承Animal。
class Animal
{
public:
Animal(QString owner = "无主人") {
this->m_owner = owner;
qDebug() << "【Animal 初始化】动物的主人:" << m_owner;
}
protected:
QString m_owner;
};
class Dog : public Animal
{
public:
Dog(QString owner = "无主人");
// 子类专属方法
void bark();
private:
QString m_breed; // 狗的品种
};
// Dog的构造函数
Dog::Dog(QString owner)
: Animal(owner) // 重点!!!!
, m_breed("金毛") //m_breed = "金毛"
{
qDebug() << "【Dog 初始化】狗的专属能力已就绪(摇尾巴/叫)";
qDebug() << "狗的品种:" << m_breed;
}
// bark 实现
void Dog::bark() {
qDebug() << "【" << m_breed << "】对着 " << m_owner<< " 叫:汪汪汪!"; 吗?
}
int main()
{
// 两种
Dog dog1("小明"); // 指定主人
dog1.bark();
Dog dog2; // 默认,无主人,Dog(QString owner = "无主人");
dog2.bark();
return 0;
}
//灵活一点
class Dog : public Animal {
public:
// 声明:支持自定义品种+主人,都给默认值(符合 Qt 构造函数风格)
explicit Dog(QString breed = "金毛", QString owner = "无主人");
void bark();
private:
QString m_breed;
};
// 定义:参数和声明完全一致,不重复写默认参数
Dog::Dog(QString breed, QString owner)
: Animal(owner) // 先初始化父类(主人)
, m_breed(breed) // 再初始化子类专属属性(品种)
{
qDebug() << "【Dog 初始化】狗的品种:" << m_breed;
}
int main()
{
Dog dog1; // 默认:金毛 + 无主人
dog1.bark(); // 【金毛】对着 无主人 叫:汪汪汪!
Dog dog2("哈士奇"); // 自定义品种:哈士奇 + 默认主人
dog2.bark(); // 【哈士奇】对着 无主人 叫:汪汪汪!
Dog dog3("柴犬", "小红"); // 自定义品种+主人
dog3.bark(); // 【柴犬】对着 小红 叫:汪汪汪!
return 0;
}
C++ 规则:创建子类对象,先把父类那一部分构造好,再构造子类自己新增的部分。
#include <iostream>
using namespace std;
class Base{
public:
Base(int a){
cout << "父类Base构造,a=" << a << endl;
}
};
class Son : public Base{
public:
// 给参数默认值 99
Son(int x = 99) : Base(x)
{
cout << "子类Son构造 x=" << x << endl;
}
};
int main()
{
Son s; // ✅不传参,x使用默认值99 → Base(99)
// Son s(); // ❌ 声明一个返回Son、无参数的函数s,不创建对象!不会调用构造!
Son s2(10); // ✅传参 x=10 → Base(10)
return 0;
}
输出:
父类Base构造,a=99
子类Son构造 x=99
父类Base构造,a=10
子类Son构造 x=10
### 如果父类是带参构造,不写初始化列表会直接编译报错!
class Base{
public:
Base(int a){} //只有带参构造,没有无参Base()
};
class Son : public Base{
public:
Son(int x)
{
// 编译器尝试自动 Base(); 但是Base没有无参构造!直接编译报错!
}
};
编译器会试图自动调用父类无参构造;父类没有,就报错。
所以必须手动写 `Son(int x):Base(x){}`。