Qt和Delphi在面向对象时使用virtual不同之处?

问题现象:使用Qt在做OSG开发时,我需要建立点、线、面的实体,这时使用初始化方法时,发现都是使用的基类的方法。

问题原因:在Qt(包括该死的C++)中使用virtual和Delphi中有手法上的不同。

问题处理:在派生类中再调用一次初始化方法,或者是参数创建方法。

代码展示:

Qt版本:

.pro文件是原生的,没有修改

 1 QT       += core gui
 2 
 3 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
 4 
 5 CONFIG += c++11
 6 
 7 # The following define makes your compiler emit warnings if you use
 8 # any Qt feature that has been marked deprecated (the exact warnings
 9 # depend on your compiler). Please consult the documentation of the
10 # deprecated API in order to know how to port your code away from it.
11 DEFINES += QT_DEPRECATED_WARNINGS
12 
13 # You can also make your code fail to compile if it uses deprecated APIs.
14 # In order to do so, uncomment the following line.
15 # You can also select to disable deprecated APIs only up to a certain version of Qt.
16 #DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
17 
18 SOURCES += 
19     main.cpp 
20     mainwindow.cpp
21 
22 HEADERS += 
23     mainwindow.h
24 
25 FORMS += 
26     mainwindow.ui
27 
28 # Default rules for deployment.
29 qnx: target.path = /tmp/$${TARGET}/bin
30 else: unix:!android: target.path = /opt/$${TARGET}/bin
31 !isEmpty(target.path): INSTALLS += target
View Code

main.h文件是原生的,没有修改

 1 #include "mainwindow.h"
 2 
 3 #include <QApplication>
 4 
 5 int main(int argc, char *argv[])
 6 {
 7     QApplication a(argc, argv);
 8     MainWindow w;
 9     w.show();
10     return a.exec();
11 }
View Code

mainwindow.h 增加了三个测试类

 1 #ifndef MAINWINDOW_H
 2 #define MAINWINDOW_H
 3 
 4 #include <QMainWindow>
 5 #include <QDebug>
 6 
 7 // 测试类
 8 class ta :public QObject
 9 {
10 public:
11     ta();
12     int id;
13     virtual void init();
14 };
15 // 测试类
16 class tb : public ta
17 {
18 public:
19     tb();
20     virtual void init() override;
21 };
22 // 测试类
23 class tc : public ta
24 {
25 public:
26     tc();
27     virtual void init() override;
28 };
29 
30 
31 QT_BEGIN_NAMESPACE
32 namespace Ui { class MainWindow; }
33 QT_END_NAMESPACE
34 
35 class MainWindow : public QMainWindow
36 {
37     Q_OBJECT
38 
39 public:
40     MainWindow(QWidget *parent = nullptr);
41     ~MainWindow();
42 
43 private slots:
44     void on_pushButton_clicked();
45 
46 private:
47     Ui::MainWindow *ui;
48     QList<ta *> olist;
49 };
50 #endif // MAINWINDOW_H
View Code

mainwindow.cpp三个类的实现,在创建事件下建立测试类的实体对象

 1 #include "mainwindow.h"
 2 #include "ui_mainwindow.h"
 3 
 4 MainWindow::MainWindow(QWidget *parent)
 5     : QMainWindow(parent)
 6     , ui(new Ui::MainWindow)
 7 {
 8     ui->setupUi(this);
 9 
10     tb *ob = new tb();
11     ob->init();// 调用派生类初始化方法
12     olist.append(ob);
13     qDebug() << ob->id;
14 
15     tc *oc = new tc();
16     oc->init();// 调用派生类初始化方法
17     olist.append(oc);
18     qDebug() << oc->id;
19 }
20 
21 MainWindow::~MainWindow()
22 {
23     delete ui;
24 }
25 
26 
27 void MainWindow::on_pushButton_clicked()
28 {
29   for (int i = 0; i < olist.size(); i++)
30   {
31       tb *ob = dynamic_cast<tb *>(olist[i]);
32       if (ob)
33       qDebug() << ob->id;
34   }
35 }
36 
37 ta::ta()
38 {
39     init();
40 }
41 
42 void ta::init()
43 {
44     id = 1;
45 }
46 
47 tb::tb()
48    : ta()
49 {
50 
51 }
52 
53 void tb::init()
54 {
55     id = 2;
56 }
57 
58 tc::tc()
59 {
60 
61 }
62 
63 void tc::init()
64 {
65     id = 3;
66 }
View Code

总结:如果不调用“ob->init();// 调用派生类初始化方法”的话,会自动调用基类的初始化。必须手机调一下自己的初始化方法。

Delphi版本:

 1 unit Unit1;
 2 
 3 interface
 4 
 5 uses
 6   Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
 7   Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
 8 
 9 type
10   //测试类
11   Ta = class(Tobject)
12   public
13     ID: integer;
14     procedure setID(); virtual;
15     constructor Create();
16   end;
17   //测试类
18   Tb = class(Ta)
19   public
20     procedure setID(); override;
21   end;
22   //测试类
23   Tc = class(Ta)
24   public
25     procedure setID(); override;
26   end;
27 
28   TForm1 = class(TForm)
29     procedure FormCreate(Sender: TObject);
30   private
31     { Private declarations }
32   public
33     { Public declarations }
34   end;
35 
36 var
37   Form1: TForm1;
38 
39 implementation
40 
41 {$R *.dfm}
42 
43 { Ta }
44 
45 constructor Ta.Create;
46 begin
47   inherited;
48   setID;
49 end;
50 
51 procedure Ta.setID;
52 begin
53   id := 1;
54 end;
55 
56 { Tb }
57 
58 procedure Tb.setID;
59 begin
60   inherited;
61   id := 2;
62 end;
63 
64 { Tc }
65 
66 procedure Tc.setID;
67 begin
68   inherited;
69   id := 3;
70 end;
71 
72 procedure TForm1.FormCreate(Sender: TObject);
73 var
74   ob: Tb;
75   oc: Tc;
76 begin
77   ob := Tb.Create(); //调用自己的初始化
78   oc := Tc.Create(); //调用自己的初始化
79 end;
80 
81 end.
View Code

总结:如果使用了“virtual”和“override”的话,如果用派生类实例实体对象,会直接调用派生成的初始化方法。

原文地址:https://www.cnblogs.com/FKdelphi/p/13605517.html