使用模板动态转换类层次结构

发布于 2024-12-22 04:50:04 字数 6371 浏览 1 评论 0原文

在我的项目中,如果我将基类Base_Dialog定义为非模板,然后尝试在already_exists_中分配“调用者”,它会按预期的方式工作,但如果我将Base_Dialog作为模板类,那么算法“already_exists_”(未更改)将不起作用并且调用者不会改变(这一点特别有趣,算法没有改变,但一旦有效,其他时候则无效):

//This is minimal example (I know it's somewhat longer than usual but in order to show what I mean it needs to be this length)

MAIN_DIALOG_HPP

    #ifndef MAIN_DIALOG_HPP
    #define MAIN_DIALOG_HPP
    #include <QSet>
    #include <QtDebug>
    #include "Base_Dialog.hpp"
    #include "ui_Main_Dialog.h"
    #include "_1Dialog.hpp"
    #include "_2Dialog.hpp"
/*The following approach will not work*/
    class Main_Dialog : public Base_Dialog<Ui::Main_Dialog>
    {
/*but if I would do as below (changing Base_Dialog to non-template) it will work:*/
//class Main_Dialog : public QDialog, private Ui::Main_Dialog, public Base_Dialog
        Q_OBJECT
        QSet<QDialog*>* dialogs_;
    private:
        template<class Dialog,class Caller>
        bool already_created_(Caller*const&, QDialog*& already_exists);

        template<class Dialog,class Caller, class Parent>
        QDialog* create_(Caller*const&,Parent*const&);

    public:
        explicit Main_Dialog(QWidget *parent = 0);
        template<class Dialog,class Caller>
        QDialog* get_dialog(Caller*const& caller);
    public slots:
        void _1clicked()
        {
            this->hide();
            get_dialog<_1Dialog>(this)->show();
        }
        void _2clicked()
        {
            this->hide();
            get_dialog<_2Dialog>(this)->show();
        }
    };

    template<class Dialog,class Caller>
    bool Main_Dialog::already_created_(Caller*const& caller,QDialog*& already_exists)
    {/*the already_exists is introduced here in order to remove repetions of code and
       searching*/
        auto beg = dialogs_->begin();
        auto end = dialogs_->end();
        while(beg != end)
        {
            if(dynamic_cast<Dialog*>(*beg))
            {
                already_exists = *beg;
                static_cast<Base_Dialog*>(already_exists)->set_caller(caller);
                return true;
            }

            ++beg;
        }
        return false;
    }

    template<class Dialog,class Caller, class Parent>
    QDialog* Main_Dialog::create_(Caller *const&caller, Parent *const&parent)
    {
        return (*dialogs_->insert(new Dialog(this,caller,parent)));
    }

    template<class Dialog,class Caller>
    QDialog* Main_Dialog::get_dialog(Caller *const&caller)
    {
        QDialog* already_exists = nullptr;
        if (already_created_<Dialog>(caller,already_exists))
        {
            return already_exists;
        }
        else
        {
            return create_<Dialog>(caller,this);
        }
    }

    Main_Dialog::Main_Dialog(QWidget *parent) :
        Base_Dialog<Ui::Main_Dialog>(this,this,parent),dialogs_(new QSet<QDialog*>)
    {
        setupUi(this);
    }

    #endif // MAIN_DIALOG_HPP

BASE_DIALOG_HPP

#ifndef BASE_DIALOG_HPP
#define BASE_DIALOG_HPP
#include <QDialog>
#include <QString>

class Main_Dialog;
template<class Ui_Dialog>
class Base_Dialog : public QDialog, protected Ui_Dialog
{
   // Q_OBJECT //no signals/slots
protected:
    Main_Dialog* main_dlg_;
    QDialog* caller_;

public:
    Base_Dialog(Main_Dialog *const &main_dlg, QDialog *const&caller, QWidget *parent = nullptr);
    QDialog* set_caller(QDialog *const&);
    QDialog* clear_caller();
    Main_Dialog* clear_main_dlg();

};

/*----------------*/
//#include "Main_Dialog.hpp"
template<class Ui_Dialog>
Base_Dialog<Ui_Dialog>::Base_Dialog(Main_Dialog *const&main_dlg,QDialog *const&caller, QWidget *parent):
    QDialog(parent),
    main_dlg_(main_dlg),
    caller_(caller)
{
    //setupUi(this);
}


#include <QtDebug>
template<class Ui_Dialog>
QDialog* Base_Dialog<Ui_Dialog>::set_caller(QDialog *const&new_caller)
{
 QDialog* old_caller = caller_;

 caller_ = new_caller;

 return old_caller;
}
#endif

_1DIALOG_HPP

#ifndef _1DIALOG_HPP
#define _1DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__1Dialog.h"

class Main_Dialog;
class _1Dialog : public Base_Dialog<Ui::_1Dialog>
{
    Q_OBJECT
public:
    explicit _1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);

private slots:
    void _2clicked();
    void caller_clicked();
    void main_clicked();
};

#endif // _1DIALOG_HPP

_1Dialog cpp

//_1Dialog cpp
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
#include "Main_Dialog.hpp"
_1Dialog::_1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
    Base_Dialog<Ui::_1Dialog>(main_dlg,caller,parent)
{
    setupUi(this);
}

void _1Dialog::_2clicked()
{
    this->hide();
    main_dlg_->get_dialog<_2Dialog>(this)->show();
}


void _1Dialog::caller_clicked()
{
    this->hide();
    caller_->show();
}

void _1Dialog::main_clicked()
{
    this->hide();
    main_dlg_->show();
}

_2DIALOG_HPP

#ifndef _2DIALOG_HPP
#define _2DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__2Dialog.h"
class Main_Dialog;
class _2Dialog : public Base_Dialog<Ui::_2Dialog>//,private Ui::_2Dialog
{
    Q_OBJECT
private:


public:
    explicit _2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);
private slots:
    void _1clicked();
    void caller_clicked();
    void main_clicked();
};

#endif // _2DIALOG_HPP

_2Dialog cpp

//_2Dialog cpp
#include "_2Dialog.hpp"
#include "_1Dialog.hpp"
#include "Main_Dialog.hpp"

_2Dialog::_2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
    Base_Dialog<Ui::_2Dialog>(main_dlg,caller,parent)
{
    setupUi(this);
}


void _2Dialog::_1clicked()
{
    this->hide();
    main_dlg_->get_dialog<_1Dialog>(this)->show();
}

void _2Dialog::caller_clicked()
{
    this->hide();
    caller_->show();
}

void _2Dialog::main_clicked()
{
    this->hide();
    main_dlg_->show();
}

为什么会出现这种情况?算法没有改变,但一旦分配正确,而另一次分配不正确?

in my project if I define base class Base_Dialog as non template and then try to assign 'caller' in already_exists_ it works in the way expected but if I make Base_Dialog as a template class then the algorithm 'already_exists_' (unchanged) will not work and caller will not change (this is especially intriguing that the algorithm is unchanged and yet once works and other time it doesn't):

//This is minimal example (I know it's somewhat longer than usual but in order to show what I mean it needs to be this length)

MAIN_DIALOG_HPP

    #ifndef MAIN_DIALOG_HPP
    #define MAIN_DIALOG_HPP
    #include <QSet>
    #include <QtDebug>
    #include "Base_Dialog.hpp"
    #include "ui_Main_Dialog.h"
    #include "_1Dialog.hpp"
    #include "_2Dialog.hpp"
/*The following approach will not work*/
    class Main_Dialog : public Base_Dialog<Ui::Main_Dialog>
    {
/*but if I would do as below (changing Base_Dialog to non-template) it will work:*/
//class Main_Dialog : public QDialog, private Ui::Main_Dialog, public Base_Dialog
        Q_OBJECT
        QSet<QDialog*>* dialogs_;
    private:
        template<class Dialog,class Caller>
        bool already_created_(Caller*const&, QDialog*& already_exists);

        template<class Dialog,class Caller, class Parent>
        QDialog* create_(Caller*const&,Parent*const&);

    public:
        explicit Main_Dialog(QWidget *parent = 0);
        template<class Dialog,class Caller>
        QDialog* get_dialog(Caller*const& caller);
    public slots:
        void _1clicked()
        {
            this->hide();
            get_dialog<_1Dialog>(this)->show();
        }
        void _2clicked()
        {
            this->hide();
            get_dialog<_2Dialog>(this)->show();
        }
    };

    template<class Dialog,class Caller>
    bool Main_Dialog::already_created_(Caller*const& caller,QDialog*& already_exists)
    {/*the already_exists is introduced here in order to remove repetions of code and
       searching*/
        auto beg = dialogs_->begin();
        auto end = dialogs_->end();
        while(beg != end)
        {
            if(dynamic_cast<Dialog*>(*beg))
            {
                already_exists = *beg;
                static_cast<Base_Dialog*>(already_exists)->set_caller(caller);
                return true;
            }

            ++beg;
        }
        return false;
    }

    template<class Dialog,class Caller, class Parent>
    QDialog* Main_Dialog::create_(Caller *const&caller, Parent *const&parent)
    {
        return (*dialogs_->insert(new Dialog(this,caller,parent)));
    }

    template<class Dialog,class Caller>
    QDialog* Main_Dialog::get_dialog(Caller *const&caller)
    {
        QDialog* already_exists = nullptr;
        if (already_created_<Dialog>(caller,already_exists))
        {
            return already_exists;
        }
        else
        {
            return create_<Dialog>(caller,this);
        }
    }

    Main_Dialog::Main_Dialog(QWidget *parent) :
        Base_Dialog<Ui::Main_Dialog>(this,this,parent),dialogs_(new QSet<QDialog*>)
    {
        setupUi(this);
    }

    #endif // MAIN_DIALOG_HPP

BASE_DIALOG_HPP

#ifndef BASE_DIALOG_HPP
#define BASE_DIALOG_HPP
#include <QDialog>
#include <QString>

class Main_Dialog;
template<class Ui_Dialog>
class Base_Dialog : public QDialog, protected Ui_Dialog
{
   // Q_OBJECT //no signals/slots
protected:
    Main_Dialog* main_dlg_;
    QDialog* caller_;

public:
    Base_Dialog(Main_Dialog *const &main_dlg, QDialog *const&caller, QWidget *parent = nullptr);
    QDialog* set_caller(QDialog *const&);
    QDialog* clear_caller();
    Main_Dialog* clear_main_dlg();

};

/*----------------*/
//#include "Main_Dialog.hpp"
template<class Ui_Dialog>
Base_Dialog<Ui_Dialog>::Base_Dialog(Main_Dialog *const&main_dlg,QDialog *const&caller, QWidget *parent):
    QDialog(parent),
    main_dlg_(main_dlg),
    caller_(caller)
{
    //setupUi(this);
}


#include <QtDebug>
template<class Ui_Dialog>
QDialog* Base_Dialog<Ui_Dialog>::set_caller(QDialog *const&new_caller)
{
 QDialog* old_caller = caller_;

 caller_ = new_caller;

 return old_caller;
}
#endif

_1DIALOG_HPP

#ifndef _1DIALOG_HPP
#define _1DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__1Dialog.h"

class Main_Dialog;
class _1Dialog : public Base_Dialog<Ui::_1Dialog>
{
    Q_OBJECT
public:
    explicit _1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);

private slots:
    void _2clicked();
    void caller_clicked();
    void main_clicked();
};

#endif // _1DIALOG_HPP

_1Dialog cpp

//_1Dialog cpp
#include "_1Dialog.hpp"
#include "_2Dialog.hpp"
#include "Main_Dialog.hpp"
_1Dialog::_1Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
    Base_Dialog<Ui::_1Dialog>(main_dlg,caller,parent)
{
    setupUi(this);
}

void _1Dialog::_2clicked()
{
    this->hide();
    main_dlg_->get_dialog<_2Dialog>(this)->show();
}


void _1Dialog::caller_clicked()
{
    this->hide();
    caller_->show();
}

void _1Dialog::main_clicked()
{
    this->hide();
    main_dlg_->show();
}

_2DIALOG_HPP

#ifndef _2DIALOG_HPP
#define _2DIALOG_HPP
#include "Base_Dialog.hpp"
#include "ui__2Dialog.h"
class Main_Dialog;
class _2Dialog : public Base_Dialog<Ui::_2Dialog>//,private Ui::_2Dialog
{
    Q_OBJECT
private:


public:
    explicit _2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent = 0);
private slots:
    void _1clicked();
    void caller_clicked();
    void main_clicked();
};

#endif // _2DIALOG_HPP

_2Dialog cpp

//_2Dialog cpp
#include "_2Dialog.hpp"
#include "_1Dialog.hpp"
#include "Main_Dialog.hpp"

_2Dialog::_2Dialog(Main_Dialog* main_dlg, QDialog*caller, QWidget *parent) :
    Base_Dialog<Ui::_2Dialog>(main_dlg,caller,parent)
{
    setupUi(this);
}


void _2Dialog::_1clicked()
{
    this->hide();
    main_dlg_->get_dialog<_1Dialog>(this)->show();
}

void _2Dialog::caller_clicked()
{
    this->hide();
    caller_->show();
}

void _2Dialog::main_clicked()
{
    this->hide();
    main_dlg_->show();
}

Why is this behavior? Algorithm is unchanged and yet once it assigns correctly and the other time it doesn't?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

¢好甜 2024-12-29 04:50:04

在 has_exists_ 中将 line: 更改

static_cast<Base_Dialog*>(already_exists)->set_caller(caller);  

为:

static_cast<Dialog*>(already_exists)->set_caller(caller);

并在 Base_Dialog @sehe 中为 QDialog 添加虚拟继承

,我要感谢您为我指明了正确的方向,这使我能够解决这个问题。非常感谢,+1;

In already_exists_ change line:

static_cast<Base_Dialog*>(already_exists)->set_caller(caller);  

to:

static_cast<Dialog*>(already_exists)->set_caller(caller);

and add virtual inheritance for QDialog in Base_Dialog

@sehe, I want to thank you for pointing me into right direction, which allow me to resolve this problem. Great thanks, +1;

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文