簡體   English   中英

如何在C ++中自動將代碼添加到派生函數中

[英]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界面。

這也允許您將派生類用作ServerClient

我會考慮將這個庫分成三個庫:一個包含大多數內容的基本庫,一個僅服務器庫和一個僅客戶端庫。 只要客戶端不使用服務器庫,您就會很好。 您最終可能會添加一些額外的類(類Processor可能會拆分為BaseProcessorClientProcessorServerProcessor ,其中每個子類都有一個基本沒有的附加功能。)

如果這不起作用,你可以將服務器/客戶端檢查在類構造函數中,並在那里調用斷言嗎? (只有當服務器或僅客戶端對於類而言是粒度而不是方法時,這才有效。)

如果這不起作用,根據它是服務器還是客戶端構建,實際編譯庫的不同版本是否有意義? 使用#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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM