Varësia rrethore e shabllonit - klasa të veçanta në skedarë të ndryshëm

para së gjithash, dua të them se jam i vetëdijshëm se kjo lloj pyetjeje është bërë më parë (p.sh. këtu Zgjidhja e një varësie rrethore midis klasave të modeleve).

Megjithatë, kjo zgjidhje (Ndarja e deklaratës nga zbatimi) funksionon vetëm kur vendosen të dyja klasat në një skedar. Në rastin tim, unë kam një StateManager dhe një klasë State, të cilat të dyja janë mjaft të mëdha dhe të garantuara për t'u rritur. Kështu, mbajtja e tyre në një skedar të madh më duket e pakënaqshme.

Këtu janë disa pjesë të rëndësishme të kodit:

// Forward declare the StateManager --> does not work (incomplete type)
class State
{
public:
    template <class TData>
    void RequestStackPush(ID stateId, std::shared_ptr<TData> data);
private:
    StateManager & stataManager;
}

Këtu është zbatimi i metodës RequestStackPush()

template<class TData>
    inline void State::RequestStackPush(ID stateId, std::shared_ptr<TData> data)
    {
        // Uses the state manager's PushState() method - here the issue with the incomplete type arises
        stateManager.PushState<TData>(stateId, data);
    }

Natyrisht, StateManager përdor klasën State gjatë gjithë kohës. Ai krijon atë që quan metoda etj. kështu që deklarimi përpara nuk është zgjidhje këtu. Vetëm për t'ju dhënë një shembull:

template<class TData>
    inline void StateManager::PushState(State::ID stateId, std::shared_ptr<TData> data)
    {
        std::unique_ptr<BasePendingChange> pendingChange = std::make_unique<PendingPushDataChange<TData>>(Push, stateId, data);
        pendingChangeQueue.push(std::move(pendingChange));
    }

Aktualisht, të dyja klasat janë në një skedar të madh. Së pari, deklarimi i klasës State me StateManager duke u deklaruar përpara, i ndjekur nga deklarimi i klasës StateManager i ndjekur nga zbatimi i metodës State::RequestStackPush() të përshkruar më sipër dhe në fund zbatimi i të gjitha metodave të modelit StateManager.

Si mund ta ndaj këtë në dy skedarë të ndryshëm?


person Adrian Albert Koch    schedule 14.12.2017    source burimi
comment
A keni menduar thjesht të hiqni metodën StateManager dhe RequestStackPush referencë? Sa e keqe do të ishte kjo për pjesën tjetër të kodit tuaj?   -  person Sebastian Redl    schedule 14.12.2017
comment
E keqe pasi është thelbësore për të qenë në gjendje t'i kalosh çdo të dhënë një shteti të prejardhur. Shtytja e gjendjes së kërkesës nevojitet për të vonuar krijimin e gjendjes së shtyrë. Krijimi i një gjendjeje gjatë përditësimit ose paraqitjes së stivit të gjendjes mund të çojë në gabime   -  person Adrian Albert Koch    schedule 14.12.2017
comment
Dua të them, pse njerëzit nuk mund të përdorin drejtpërdrejt StateManager::PushState?   -  person Sebastian Redl    schedule 14.12.2017
comment
@SebastianRedl Meqenëse, siç thashë, kjo mund ose në të vërtetë do të ndërpresë ciklin e përditësimit në të cilin grupi i gjendjes është i lidhur   -  person Adrian Albert Koch    schedule 14.12.2017


Përgjigjet (1)


Megjithatë, kjo zgjidhje (Ndarja e deklaratës nga zbatimi) funksionon vetëm kur vendosen të dyja klasat në një skedar.

Jo, nuk funksionon vetëm në një skedar. Gjithmonë mund të ndërtoni një skedar identik duke përfshirë nëntituj. Thjesht kërkon që ju të bëni diçka që do të ishte e pazakontë me jo shabllonet (edhe pse e njëjta teknikë funksionon me të gjitha përkufizimet e funksioneve inline): Duhet të përfshini një skedar pas përcaktimit të klasës. Titujt nuk kufizohen në të qenit në krye të skedarit pavarësisht nga emri që u është dhënë.

Pra, në një skedar:

  • deklaro StateManager
  • Përcaktoni State
  • Përfshi përkufizimin e StateManager
  • Përcaktoni funksionet e anëtarëve që varen nga përkufizimi i StateManager

Asgjë e pazakontë në skedarin tjetër:

  • Përfshi përkufizimin e State
  • Përcaktoni StateManager dhe funksionet e tij anëtare.

Rezultati përfundimtar është se përfshirja e secilit titull prodhon të njëjtat përkufizime dhe deklarata në rendin e kërkuar. Pra, kjo ndarje e skedarëve nuk ndihmon në asnjë mënyrë për të kufizuar sasinë e ripërpilimit të shkaktuar nga modifikimi i një prej titujve.

Mund të jetë çështje shije, por unë gjithmonë përfshij përkufizime të kërkuara nga funksionet inline (duke përfshirë anëtarët e modeleve dhe funksionet e shabllonit) pas përkufizimit të klasës. Në këtë mënyrë nuk kam nevojë të shqetësohem nëse është e nevojshme ta bëj këtë.

person eerorika    schedule 14.12.2017
comment
Ai ka nevojë për përkufizimin e plotë të State përpara përkufizimit të StateManager meqenëse disa nënshkrime funksioni referojnë llojet e brendshme. Por ideja e përgjithshme është e drejtë. - person Sebastian Redl; 14.12.2017
comment
@SebastianRedl ah, nuk e vura re se varësia ishte në argument. Rregullim... Rregulluar. - person eerorika; 14.12.2017
comment
@AdrianKoch State.h nuk duhet të përfshijë StateManager.h përpara se State të jetë përcaktuar. Përndryshe ka një varësi rrethore. Ju duhet të heqni qafe atë përfshirje. Nuk është e mundur të thuhet se si, pa një shembull minimal të riprodhueshëm. - person eerorika; 14.12.2017
comment
Truku tjetër që mund të përdorni në çdo kokë fëmijë është të pohoni se titulli prind është ngarkuar, kështu që renditja juaj është ruajtur. Titujt standardë janë plot me shembuj si: #if !defined _MATH_H && !defined _COMPLEX_H # error Asnjëherë mos përdorni ‹bits/mathdef.h› drejtpërdrejt; përfshini ‹math.h› në vend të #endif - person Gem Taylor; 14.12.2017