[英]How do I add code automatically to a derived function in C++
我的代碼用於管理網絡客戶端和服務器上的操作,因為兩者之間存在顯着的重疊。 但是,這里和那里有一些函數意味着由客戶端或服務器專門調用,並且意外調用服務器上的客戶端函數(反之亦然)是錯誤的重要來源。
為了減少這些編程錯誤,我正在嘗試標記函數,以便在它們被濫用時引起騷動。 我當前的解決方案是每個函數啟動時的一個簡單宏,如果客戶端或服務器訪問不應該訪問的成員,則調用斷言。 但是,當存在多個派生類的實例時,這會遇到問題,因為我必須在每個子類中將實現標記為客戶端或服務器端。
我希望能夠做的是在基類中的虛擬成員的簽名中放置一個標記,這樣我只需要標記一次而不會因忘記重復執行而導致錯誤。 我已經考慮過對基類實現進行檢查,然后用類似base :: functionName的方法引用它,但是只要需要手動將函數調用添加到每個實現,就會遇到同樣的問題。 理想情況下,我可以像默認構造函數那樣自動調用函數的父版本。
有人知道如何用C ++實現這樣的東西嗎? 我應該考慮采用另一種方法嗎?
謝謝!
另一種方法可能是覆蓋與調用者實際調用的方法不同的方法:
class Base {
public:
void doit(const Something &);
protected:
virtual void real_doit(const Something &);
};
class Derived: public Base {
protected:
virtual void real_doit(const Something &);
};
Base::doit()
可以進行檢查以確保在正確的環境中調用它,然后調用虛擬的real_doit()
函數。 派生類將覆蓋受保護的虛函數,並且任一類的用戶都無法調用受保護的函數。
Base::doit()
函數不是虛函數,因此派生類不會意外地覆蓋錯誤的類。 (人們可以嘗試,但希望他們很快就會注意到它沒有被調用。)
你提出的建議非常復雜。 這聽起來像一個更簡單的解決方案
class CommonStuff {
// all common code that anybody can safely call
};
class ServerBase : public CommonStuff {
// only what the server is allowed to call; can safely be overwritten
};
class ClientBase : public CommonStuff {
// only what the client is allowed to call; can safely be overwritten
};
編譯時強制比任何類型的運行時強制要好得多。
在沒有重新設計課程的情況下,語言(我知道)中沒有辦法做你要求的。 最簡單的解決方案可能是擁有一個不聲明服務器功能的Client
接口(純虛擬)類,以及一個不聲明客戶端功能的Server
接口類,並使您的整合代碼從兩個接口繼承(公開)。 然后在客戶端程序中,使用Client
接口的引用(或指針),該接口不允許訪問未在Client
接口中聲明的任何方法。 在服務器上,使用“ Server
界面。
這也允許您將派生類用作Server
或Client
。
我會考慮將這個庫分成三個庫:一個包含大多數內容的基本庫,一個僅服務器庫和一個僅客戶端庫。 只要客戶端不使用服務器庫,您就會很好。 您最終可能會添加一些額外的類(類Processor
可能會拆分為BaseProcessor
, ClientProcessor
和ServerProcessor
,其中每個子類都有一個基本沒有的附加功能。)
如果這不起作用,你可以將服務器/客戶端檢查在類構造函數中,並在那里調用斷言嗎? (只有當服務器或僅客戶端對於類而言是粒度而不是方法時,這才有效。)
如果這不起作用,根據它是服務器還是客戶端構建,實際編譯庫的不同版本是否有意義? 使用#ifdef SERVERBUILD
和#ifdef CLIENTBUILD
包圍方法及其聲明,並包含一些檢查以確保它們未定義( #if defined(SERVERBUILD) && defined(CLIENTBUILD)
, #if defined(SERVERBUILD) && defined(CLIENTBUILD)
#error Can't define both!
)。
我投了Greg Hewgill的回答,但它讓我想到了添加“方面”的方法,比如你要求的。 我在這里使用了他的命名約定(類Base
和方法doit
):
class Base {
protected:
class Aspect {
public:
Aspect(int x) {
std::cout << "aspect" << std::endl;
}
};
public:
virtual void doit(const Something &arg, const Aspect hook = 0)
{
std::cout << "doit(" << arg << ")" << std::endl;
}
};
base.doit(arg)
者可以說base.doit(arg)
因為Aspect
是默認參數。 它的構造函數在doit
之前運行,它的析構函數(未圖示)運行之后。 可悲的是我的第一個想法是使默認參數hook = this
是不允許的。
孩子們可以使用相同的簽名覆蓋doit
並獲得相同的效果。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.