2017-08-24 19 views
5

मैं भविष्य में क्यूटी 5.9 के तहत विकसित किए गए विगेट्स की लाइब्रेरी संभव बनाने के बारे में चिंतित हूं, जो भविष्य में इसे पहले से उपयोग किए जाने वाले कोड को दोबारा उपयोग किए बिना अपग्रेड किया जा सकता है। बेशक मैं pimpl मुहावरा के साथ शुरू कर दिया है और इसके बारे में Qt संस्करण here और here का वर्णन किया।क्यूटी में स्लॉट के रूप में सी ++ लैम्ब्डा फ़ंक्शंस का उपयोग करना लाइब्रेरी की बाइनरी संगतता को संरक्षित रखने में मदद करता है?

हालांकि मेरे कोड को अनुकूलित करने का प्रयास करते समय, मैं इस विचार के साथ आया कि नए डेटा सदस्यों को जोड़ने और उन्हें एक अलग निजी वर्ग में स्थानांतरित करने के बजाय, मैं कंब के सिग्नल/स्लॉट तंत्र का उपयोग लैम्ब्डा कार्यों के साथ कर सकता हूं और केवल स्थानीय चर

संस्करण एक::

class Foo : public QWidget 
{ 
    Q_OBJECT 
public: 
    explicit Foo(QWidget *parent = nullptr); 

private: 
    // A bunch of data members 
    QPushButton *m_button; 
    QLineEdit *m_lineEdit; 
    QCheckBox *m_checkBox; 
    QString m_str; 

private slots: 
    void on_pushButtonClicked(); 
    void on_checkBoxStateChanged(int state); 
}; 

Foo::Foo(QWidget *parent) : 
    QWidget(parent), 
    m_button(new QPushButton("Click me", this)); 
    m_lineEdit(new QLineEdit(this)), 
    m_checkBox(new QCheckBox(this)), 
    m_str("Initial text") 
{ 
    connect(button, &QPushButton::clicked, this, &Foo::on_pushButtonClicked); 
    connect(checkBox, &QCheckBox::stateChanged, this, &Foo::on_checkBoxStateChanged); 
} 

Foo::on_pushButtonClicked() 
{ 
    m_str = m_lineEdit->text(); 
    m_lineEdit->setDisabled(m_checkBox->isChecked()); 
} 

Foo::on_checkBoxStateChanged(int state) 
{ 
    m_button->setText(state == Qt::Checked ? m_str : "Click me") 
} 

संस्करण बी: के निम्न उदाहरण के साथ विचार को वर्णन करते संस्करण बी के लिए

class Foo : public QWidget 
{ 
    Q_OBJECT 
public: 
    explicit Foo(QWidget *parent = nullptr); 
}; 

Foo::Foo(QWidget *parent) : QWidget(parent) 
{ 
    QPushButton *button = new QPushButton("Click me", this); 
    QLineEdit *lineEdit = new QLineEdit(this); 
    QCheckBox *checkBox = new QCheckBox(this); 
    QString str("Initial text"); 

    connect(button, &QPushButton::clicked, [=](){ 
     str = lineEdit->text(); 
     lineEdit->setDisabled(checkBox->isChecked()); 
    }); 

    connect(checkBox, &QCheckBox::stateChanged, [=](int state){ 
     button->setText(state == Qt::Checked ? str : "Click me") 
    }); 
} 

तो, - अलग अधिक कॉम्पैक्ट होने से , इसमें कोई क्लास डेटा सदस्य नहीं है, इसलिए छिपाने के लिए कोई चर नहीं है, इसलिए डी-पॉइंटर की आवश्यकता नहीं है। बाइनरी संगतता अभी भी गारंटीकृत है (या यह है?), अगर भविष्य में कन्स्ट्रक्टर को उसी सिग्नल/स्लॉट तरीके से उपयोग किए गए अतिरिक्त स्थानीय चर के साथ पुन: कार्यान्वित किया जाता है। क्या मुझे लगता है कि यह काम करेगा या ऐसा दृष्टिकोण चाल नहीं करेगा?

नोट: lambdas का उपयोग कर के रूप में क्यूटी में स्लॉट @Igor Tandetnik here द्वारा टिप्पणी की जांच के बारे में अधिक जानकारी के लिए।

+0

मुझे नहीं लगता कि संकलन करेंगे। लैम्बडा के अंदर 'str' होगा। यहां तक ​​कि यदि यह संकलित करता है, तो ध्यान दें कि आप मूल्य से कैप्चर करते हैं: उन दो अलग-अलग लैम्बडा में 'str' अलग-अलग, स्वतंत्र वस्तुओं को संदर्भित करता है। आपको एक हीप-आवंटित सूचक द्वारा सब कुछ पकड़ना होगा - स्टेरॉयड पर एक 'पिंपल'। –

+0

@IgorTandetnik, मुझे आपका अंक मिला है। हालांकि, इस कन्स्ट्रक्टर के एकमात्र पुनर्मूल्यांकन को बाइनरी संगतता को तोड़ना नहीं चाहिए, क्या इसे चाहिए? – scopchanov

+0

मुझे यकीन नहीं है कि आपका मतलब "बाइनरी संगतता" से क्या है। जब तक आप उस शीर्षक को संशोधित नहीं करते हैं जहां 'Foo' वर्ग परिभाषित किया गया है, तो आपको' Foo' का उपयोग करके स्रोतों को पुन: संकलित करने की आवश्यकता नहीं होगी, अगर आप यही पूछ रहे हैं। उस ने कहा, आपको Variant B. की शैली में कोड का कोई महत्वपूर्ण टुकड़ा लिखने में कठिनाई होगी। सामान्य कक्षा में, आप एक निजी सदस्य फ़ंक्शन कर सकते हैं जिसे आप एकाधिक स्थानों से कॉल कर सकते हैं। अब आप कोड का पुन: उपयोग करने की योजना कैसे बना रहे हैं? प्रत्येक "सदस्य फ़ंक्शन" के लिए कन्स्ट्रक्टर में लैम्ब्डा बनाएं, और क्या सभी कनेक्शन हैंडलर इसे कैप्चर करते हैं? यह बहुत तेज बहुत तेज हो जाएगा। –

उत्तर

2

मैं

इसके बारे में सोचने के लिए गलत तरीका है कि विचार के साथ आया था, कि बजाय नए डेटा सदस्यों को जोड़ने और उन्हें एक अलग निजी दूसरी कक्षा में जाने के [...]। इंटरफ़ेस में कोई डेटा सदस्य नहीं है। आपके पास जो भी सदस्य हैं, सीधे को पीआईएमपीएल में जाएं। आप कुछ भी "स्थानांतरित" नहीं करते हैं, आप उन्हें को गलत स्थान से शुरू करने के लिए नहीं जोड़ते हैं।

इसके अलावा, सदस्यों पैरेंट ऑब्जेक्ट के रूप में ही जीवन है के ढेर आवंटन समय से पहले pessimization है। उन्हें पीआईएमपीएल में मूल्य से स्टोर करें।

[...] मैं लैम्ब्डा कार्यों के साथ क्यूटी के संकेत/स्लॉट का उपयोग कर सकते हैं और केवल स्थानीय चर

यह QObject की तुलना में अधिक कुछ स्टोर करने के लिए जैसे ही आप की जरूरत के रूप में काम नहीं करेगा संपत्ति प्रणाली का दुरुपयोग किए बिना बच्चे।

यह एक लचीला दृष्टिकोण नहीं है, और यह इसे सही ढंग से करने के लिए वास्तव में मुश्किल नहीं है। क्यूटी सभी आवश्यक पैटर्न स्थापित करता है। कुछ विवरणों के लिए this question देखें।

कक्षाएं जिन्हें आप प्राप्त करने का इरादा नहीं रखते हैं उन्हें Class_p.h शीर्षकों की आवश्यकता नहीं है। आप फ़ाइल की शुरुआत में ClassPrivate परिभाषा भी जोड़ सकते हैं।

// Foo.h 
#include <QWidget> 
class FooPrivate; 
class Foo : public QWidget { 
    Q_OBJECT 
    Q_DECLARE_PRIVATE(Foo) 
    QScopedPointer<FooPrivate> const d_ptr; 
public: 
    explicit Foo(QWidget *parent = {}); 
    ~Foo(); 
protected: 
    Foo(FooPrivate &, QWidget *parent = {}); // for expansion 
}; 
// Bar.h 
#include "Foo.h" 
class BarPrivate; 
class Bar : public Foo { 
    Q_OBJECT 
    Q_DECLARE_PRIVATE(Bar) 
    Q_PROPERTY(int data READ data) 
public: 
    explicit Bar(QWidget *parent = {}); 
    ~Bar(); 
    int data() const; 
protected: 
    Bar(BarPrivate &, QWidget *parent = {}); // for expansion 
}; 
// Foo_p.h 
#include "Foo.h" 

class FooPrivate { 
    Q_DECLARE_PUBLIC(Foo) 
    Q_DISABLE_COPY(Foo) // usually desired 
    Foo * const q_ptr; 
public: 
    QVBoxLayout m_layout{q_ptr}; 
    QPushButton m_button{q_ptr->tr("Hello!")}; 
    QLineEdit m_lineEdit; 
    QCheckBox m_checkBox{q_ptr->tr("Active")}; 

    void on_pushButtonClicked(); 
    void on_checkBoxStateChanged(int state); 

    explicit FooPrivate(Foo *); 
    virtual ~FooPrivate() {} // we're meant to be derived from! 
}; 
// Bar_p.h 
#include "Foo_p.h" 
#include "Bar.h" 

class BarPrivate : public FooPrivate { 
    Q_DECLARE_PUBLIC(Bar) 
public: 
    int m_data = 44; 

    explicit BarPrivate(Bar *); 
}; 
// Foo.cpp 
#include "Foo_p.h"  

Foo::Foo(QWidget * parent) : 
    Foo(*new FooPrivate(this), parent) 
{} 

Foo::Foo(FooPrivate & d_ptr, QWidget * parent) : 
    QWidget(parent), 
    d_ptr(d_ptr) 
{} 

Foo::~Foo() {} 

FooPrivate::FooPrivate(Foo * q_ptr) : 
    q_ptr(q_ptr) 
{ 
    m_layout.addWidget(&m_button); 
    m_layout.addWidget(&m_lineEdit); 
    m_layout.addWidget(&m_checkBox); 
    connect(&m_button, &QPushButton::clicked, [=]{ on_pushButtonClicked(); }); 
    connect(&m_checkBox, &QCheckBox::stateChanged, [=](int s){ on_checkBoxStateChanged(s); }); 
} 
// Bar.cpp 
#include "Bar_p.h" 

Bar::Bar(QWidget * parnet) : 
    Bar(*new BarPrivate(this), parent) 
{} 

Bar::Bar(BarPrivate & d_ptr, QWidget * parent) : 
    Foo(d_ptr, parent) 
{} 

Bar::~Bar() {} 

BarPrivate::BarPrivate(Bar * q_ptr) : 
    FooPrivate(q_ptr) 
{} 

int Bar::data() const { 
    Q_D(const Bar); 
    return d->m_data; 
} 
+0

सबसे पहले, व्याख्या के लिए धन्यवाद और प्रदान किया गया अच्छा उदाहरण! मुझे हालांकि जोड़ना है, कि मैंने इस कण्य प्रश्न से पहले और इस लिंक में लिंक की जांच की है, यह क्यूटी में पीआईएमपीएल का उपयोग करने के बारे में नहीं है, लेकिन इसे अन्य माध्यमों से बदला जा सकता है (उदाहरण के लिए लैम्ब्स का व्यापक उपयोग)। जहां तक ​​मैं समझता हूं, आपकी राय है - नहीं, इसे प्रतिस्थापित नहीं किया जा सकता है। "चलने" के लिए मेरा मतलब है कि मेरी लाइब्रेरी को फिर से डिजाइन करना, जो फिलहाल मुहावरे का उपयोग नहीं करता है, इसलिए इसे उसी तरह से लिखा जाना चाहिए। मुझे इसके साथ विशिष्ट समस्याएं हैं, हालांकि, मुझे लगता है कि एक नया सवाल खोलने लायक है। – scopchanov

+0

@scopchanov हाँ, कृपया एक और प्रश्न खोलें। यह देखना दिलचस्प होगा कि आप और क्या चलते हैं। –

+0

मैं इसे आज रात कर दूंगा और आपको बताए जाने के लिए अपना नाम बताऊंगा। मैं उस पर आपकी राय सुनने के लिए उत्सुक हूं। – scopchanov

संबंधित मुद्दे