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

时间:2011-12-20 07:19:52

标签: c++ templates multiple-inheritance dynamic-cast

在我的项目中,如果我将基类Base_Dialog定义为非模板,然后尝试分配' caller'在already_exists_中,它以预期的方式工作,但如果我将Base_Dialog作为模板类,那么算法已经存在_' (不变)将无法工作,调用者也不会改变(这特别有趣的是算法没有改变,但一旦工作,其他时间它不会):

//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();
}

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

1 个答案:

答案 0 :(得分:0)

在already_exists_更改行中:

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

到:

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

并在Base_Dialog中添加QDialog的虚拟继承

@sehe,我想感谢你指点我正确的方向,这让我解决了这个问题。非常感谢,+ 1;

相关问题