0%

C++复习和Qt(一)

C++复习和Qt(Ubuntu)

namespace

  • 命名空间的定义
  • namespace Ui { class MainWindow; class myThread;}
  • 一个命名空间的定义包含两部分:首先是关键字namespace,随后是命名空间的名字。
  • 在命名空间名字后面是一系列由花括号括起来的声明和定义
  • 只要能出现在全局作用域中的声明就能置于命名空间内,主要包括:类、变量(及其初始化操作)、函数(及其定义)、模板和其它命名空间。
  • 命名空间结束后无须分号,这一点与块类似。

假如在一个类中使用在之后定义的类的对象或者其他内容的话,先在这个类之前使用class <被使用的类名>;声明一下类

class <class name> : <访问权限修饰符> <super class>
{
public:
<函数定义>
protected:
<函数定义>
private:
<函数定义>
}
  • 不写权限默认private

构造函数

  • 构造函数必须与类名同名;
  • 可以重载,(重载?新概念,后面学到什么是重载。);
  • 没有返回类型,即使是 void 也不行。

析构函数

  • 析构函数的格式为~类名();
  • 调用时释放内存(资源);
  • ~类名()不能加参数;
  • 没有返回值,即使是 void 也不行。

this指针

  • this 指针记录对象的内存地址
  • this 只能在成员函数中使用,全局函数、静态函数都不能使用 this。实际上,成员函数 默认第一个参数为 T * const this。也就是一个类里面的成员了函数 int func(int p),func 的原 型在编译器看来应该是 int func(T * const this,int p)。
  • this 在成员函数的开始前构造,在成员函数的结束后清除。
  • this 指针会因编译器不同而有不同的放置位置。可能是栈,也可能是寄存器,甚至全 局变量。

继承

class <class name> : <访问权限修饰符> <super class>
  • 公有继承(public):当一个类派生继承公有基类时,基类的公有成员也是派生类的公有成 员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但 是可以通过调用基类的公有和保护成员来访问。
  • 保护继承(protected): 当一个类派生继承保护基类时,基类的公有和保护成员将成为派 生类的保护成员。
  • 私有继承(private):当一个类派生继承私有基类时,基类的公有和保护成员将成为派生类 的私有成员。

运算符重载

  • 运算符重载的实质就是函数重载或函数多态。运算符重载是一种形式的 C++多态。目的在 于让人能够用同名的函数来完成不同的基本操作。
<返回类型说明符> operator <运算符符号>(<参数表>)
{
<函数体>
}
  • 可重载的函数
    • image-20220114000140555
    • image-20220114000156524
#比如有一个dog类,具有一个属性是体重weight
class Dog
{
...
Dog operator+(const Dog &d)
{
Dog dog;
dog.weight = this->weight+d.weight;
return dog;
}
};
  • 注意传入的参数是引用传递

多态

  • C++多态意味着调用成员函数时,会根据调用函数的对象的类型来执行不同的函数

  • 也就是说用基类的指针调用子类的对象的时候,会根据子类的具体类型进行具体的函数的选择

  • 虚函数是 C++中用于实现多态(polymorphism)的机制。核心理念就是通过基类访 问派生类定义的函数

  • 多态的条件

    • 必须存在继承关系;
    • 继承关系必须有同名虚函数(其中虚函数是在基类中使用关键字 virtual 声明的函数,在派 生类中重新定义基类中定义的虚函数时,会告诉编译器不要静态链接到该函数);
    • 存在基类类型的指针或者引用,通过该指针或引用调用虚函数。

虚函数

  • 我们想要的是在程序中任意点可以根据所调用的对象类 型来选择调用的函数,这种操作被称为动态链接,或后期绑定。
  • virtual ReturnType FunctionName(Parameter)

纯虚函数

  • 若在基类中定义虚函数,以便在派生类中重新定义该函数更好地适用于对象,但是您在基 类中又不能对虚函数给出有意义的实现,这个时候就会用到纯虚函数。
  • virtual void funtion1()=0

数据封装

  • 数据封装是一种把数据和操作数据的函数捆绑在一起的机制,数据抽象是一种仅向用户暴 露接口而把具体的实现细节隐藏起来的机制,C++ 通过创建类来支持封装和数据隐藏(public、 protected、private)。

  • 简而言之就是不直接将变量暴露在用户的访问权限下而设置一个专门的函数处理用户对于变量的访问

抽象类

  • 如 果类中至少有一个函数被声明为纯虚函数,则这个类就是抽象类
  • 设计抽象类(通常称为 ABC)的目的,是为了给其他类提供一个可以继承的适当的基类。 抽象类不能被用于实例化对象,它只能作为接口使用。如果试图实例化一个抽象类的对象,会 导致编译错误。
  • 如果一个 ABC 的子类需要被实例化,则必须实现每个虚函数,这也意味着 C++ 支 持使用 ABC 声明接口。如果没有在派生类中重写纯虚函数,就尝试实例化该类的对象,会导 致编译错误。可用于实例化对象的类被称为具体类。

Linux下安装Qt

chmod +x qt-opensource-linux-x64-5.12.9.run
./qt-opensource-linux-x64-5.12.9.run
  • 安装开始会要求登录,登录之后选择安装的内容
  • image-20220114004230454

信号与槽

  • 信号(Signal)就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标 单击时发射的 clicked() 信号,一个 ComboBox 最常见的信号是选择的列表项变化时发射的 CurrentIndexChanged() 信号。
  • 槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++函数是一样的,可以 定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。 槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数 被自动执行。
QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));
  • 其中,sender 是发射信号的对象的名称,signal() 是信号名称。信号可以看做是特殊的函 数,需要带括号,有参数时还需要指明参数。receiver 是接收信号的对象名称,slot() 是槽函数 的名称,需要带括号,有参数时还需要指明参数。

  • 使用例

QObject::connect(pushButton, SIGNAL(clicked()), MainWindow, SLOT(close()));
  • 其中的pishButton是动作的发出者,MainWindow是信号的接收者

  • 一个信号可以连接多个槽

  • 多个信号也可以链接同一个槽

  • 一个信号可以连接另外一个信号

connect(pushButton, SIGNAL(objectNameChanged(QString)),this, SIGNAL(windowTitelChanged(QString)));
  • 一个信号发射时,也会发射另外一个信号,实现某些特殊的功能。

  • 断开连接使用disconnect(),此处略

信号

  • 信号只需要声明,无需定义
  • 信号需要在signals里面进行声明
  • image-20220114201719988

  • 创建槽的方法也很简单,也是直接在 mianwindow.h 里直接声明槽,在 mianwindow.cpp 里 实现槽的定义,声明槽必须写槽的定义(定义指函数体的实现),否则编译器编译时将会报错

  • 槽可以是任何成员函数、普通全局函数、静态函数

  • 槽函数和信号的参数和返回值要一致

  • image-20220114201840110

举例

  • mainwindow.h
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();

signals:
void pushBtnTxtChanged();

public slots:
void changeBtnTxt();

void pushBtnClicked();

private:
QPushButton *pushBtn;
};
#endif // MAINWINDOW_H

  • mainwindow.cpp
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
this->resize(800, 600);

pushBtn = new QPushButton(this);

pushBtn->setText("I am a Button");
connect(pushBtn, SIGNAL(clicked()), this, SLOT(pushBtnClicked()));
connect(this, SIGNAL(pushBtnTxtChanged()), this, SLOT(changeBtnTxt()));
}

MainWindow::~MainWindow()
{
delete pushBtn;
}


void MainWindow:: pushBtnClicked()
{
emit pushBtnTxtChanged();
}

void MainWindow::changeBtnTxt()
{
pushBtn->setText("clicked!");
}

  • 上面的代码中实现了自定义一个信号pushBtnTxtchanged(),将其通过自定义的槽函数pushBtnClicked()emit出来,然后连接到changeBtnTxt()函数上。通过将自定义的槽函数pushBtnClicked()连接到按钮自带的clicked()信号上,实现按下之后修改按键文字的功能。

  • image-20220114203037162

  • image-20220114203057405