[英]Qt:Signals and Slots vs C++:Message Passing
我有兩節課
class Car
{
// class Car related methods
public:
setDriversName(QString);
private:
String driversName_; // This information comes from class DriversName
//Must get the drivers name info, when a particular event in this object occurs;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
String driversName_;
}
所以,現在我想在兩個類之間進行通信,更具體地說, 當Car Object中出現特定事件時 ,我希望類Car
從DriversName
類中獲取驅動程序的名稱。
到目前為止,我有這兩種方式,
C++ Message passing:
class Car
{
// class Car related methods
public:
setDriversNameObject(DriversName& );
setDriversName()
{
driversName_ = DriversName.getDriversName();
}
private:
DriversName driversName_; // So after setting the Driverclass object, i can directly
//access the driver's name, whenever the event occurs
String driversName_;
}
class DriversName
{
//class DriversName related methods
String getDriversName();
private:
DriversName driversName_;
}
要么
Qt
In mainWindow class:
connect(carObject,eventHasOccured(),this,updateDriversName());
void MainWindow::updateDriversName()
{
carObject->setDriversName(driversNameObject.getDriversName);
}
Class Car
{
Q_OBJECT
signals:
emit eventHasOccured();
public:
setDriversNameObject(DriversName& );
private:
DriversName driversName_;
}
Class DriversName
{
Q_OBJECT
String getDriversName();
private:
DriversName driversName_;
}
兩種解決方案肯定都會有效。 這是我的問題:
1)就OO原則而言,上述方法是否存在任何缺陷。
2)這種情況可以處理的最標准方法是什么?
3)還有其他更好的方法來處理給定的情況。
謝謝。
1)就OO原則而言,上述方法是否存在任何缺陷。
第一種方法將Car
方法與DriversName
類緊密DriversName
。
第二個將您的申請與Qt聯系起來。 如果你在整個應用程序中使用它,那不是什么大問題,但應該考慮它。 此外,它將業務邏輯代碼移動到主窗口類中,這可能不是一個好主意。
2)這種情況可以處理的最標准方法是什么?
這樣做沒有“一種明確的方式”。 只是越來越好。
3)還有其他更好的方法來處理給定的情況。
對於“純C ++”方法,您可以引入一個抽象接口來監聽驅動程序名稱更改(或者甚至更一般地用於監聽通用名稱更改)。 我在這里指的是基本上實現Observer模式。 簡化的實現可以如下所示:
class NameChangeListener
{
public:
virtual void onNameChange(std::string const & newName) =0;
};
// This assumes change is initiated in DriversName class - not sure if this is correct
// Your code doesn't show the actual triggering of the change
class DriversName
{
public:
// ... other stuff
setNameChangeListener(NameChangeListener* ncl)
{
changeListener = ncl;
}
void setName(std::string const & newName)
{
// ... other stuff
if (changeListener)
changeListener->onNameChange(newName);
}
private:
// ..
NameChangeListener* changeListener;
};
class Car: public NameChangeListener
{
public:
// ... other stuff
void onNameChange(std::string const & newName) {
driversName = newName;
}
};
// somewhere outside:
Car c1;
DriversName n;
n.setNameChangeListener(c1);
對於Qt方法,可能最好引入一個封裝這種關系的附加“Controller”類,而不是直接在主窗口中進行。
在nyarlathotep的回答之上還有一些細節:
1)如果您確實需要在特定事件發生時進行更新,那么第一個解決方案是不夠的,因為它不處理事件; 一個人應該明確地調用Car
的setDriversName()
。 你需要一般的信號/插槽或回調機制,就像第二種解決方案一樣。 在那種情況下,我認為你寧願需要類似的東西
connect(driversNameObject,nameChanged(string),carObject,setDriversName(string));
應用程序/主窗口和carObject
需要知道有關driversNameObject
任何信息。 除此之外,我認為你的第二個解決方案中存在一些小錯誤(例如, Car
沒有setDriversName
方法。
2)和3)如果我還沒有在QT項目中工作,我個人會避免使用QT的信號/插槽機制。 這種機制完全繞過C ++語言,需要通過自己的工具進行源文件預處理。 一個結果是在編譯器有任何檢查機會之前,所有內容(如方法名稱)都被處理為字符串。 另一個是你需要一種特定的方式來構建你的項目,這種方式比必要的更復雜,並且會使其他庫的使用更加困難。
至於更多“純C ++”解決方案,我敢打賭,例如Boost.Signals會完成這項工作,但同樣可能會帶來太多你不需要的復雜性。
我開發了一個純C ++抽象接口,它完全模仿基於委托的QT信號/槽的行為,但這涉及內部的低級內容,如轉換為void*
。 另一種選擇當然是在內部使用std::function
。 它在處理所有函數調用語言特性時仍然不是完全通用的,例如派生類中的方法,重載,虛方法,默認參數等等(但Boost.Signals都不是)。 我打算在完成它之前使用可變參數模板在C ++ 11中重新實現它。
同樣,我(仍)不知道完美或事實上的標准解決方案。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.