2015-07-22 18 views
5

Ho una classe base di un oggetto geometrico che uso da sola ma voglio anche ereditare la classe in un'altra che è una specie di versione avanzata dell'oggetto poiché condivide molta logica. L'oggetto base ha diversi metodi di creazione statici (non può usare nuovi a causa di conflitti tra argomenti), non voglio ereditarli. Posso specificare in qualche modo che quelli non devono essere ereditati?Riesci a rendere un metodo di una classe non ereditabile?

EDIT: per includere un esempio

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 

Non voglio AdvancedBanana :: CreateByHalfLength di esistere, mentre io voglio Banana :: CreateByHalfLength ad esistere ed essere accessibile dall'esterno della classe.

+0

Cosa farebbe in realtà? Suppongo che tu voglia 'Derived :: constructBase (args, go, here)' per non funzionare? (se 'constructBase' è un metodo statico su' Base', e 'Derived' estende' Base') – immibis

+1

Se l'ho lasciato così com'è, Creerebbe solo un'istanza dell'oggetto base. Non c'è nulla di male in questo, solo confusione. Anche i metodi sono chiamati "CreateByXYZWLH" o "CreateByRxRy" ecc che sono applicabili anche alla classe derivata, quindi potrei voler riutilizzare i nomi. – user81993

+0

@immibis La risposta mi sembra diretta. Se non sbaglio, che ne dici di utilizzare una parola chiave privata? – Nabin

risposta

3

Prova questa redclare la funzione come privato nel bambino:.

#include <iostream> 
    class Banana { 
    public: 
     float length; 
     float getLenght(){ 
      return length; 
     } 
     void setLenght(float value){ 
      length = value; 
     } 
     Banana() {} 

     Banana(float length) { 
      this->length = length; 
     } 

     static Banana CreateByHalfLength(float halfLength) { 
      return Banana(halfLength * 2); 
     } 
    }; 

    class AdvancedBanana : public Banana { 
    public: 
     float bendAmt; 

     AdvancedBanana(float length, float bendAmt) { 
      this->length = length; this->bendAmt = bendAmt; 
     } 
    private: 
     static AdvancedBanana CreateByHalfLength(float halfLength); 

    }; 
    int main() 
    { 
    // work 
     Banana a(1); 
     a.CreateByHalfLength(1); 

    AdvancedBanana b(0,1); 
    //will fail 
    // b.CreateByHalfLength(1); 

    }; 
-1

Quello che stai dicendo è un po 'vago e un esempio sarebbe utile. In particolare dal momento che usi la parola static, e non è chiaro quale sia il suo contesto.

Non è possibile impedire a una classe derivata di ereditare tutti i metodi di una classe base. Il meglio che puoi fare è renderlo un non membro che richiede il parametro dell'oggetto base. Quindi dovresti downcast l'oggetto prima di chiamare, ma puoi comunque chiamarlo.

Quello che stai suggerendo sembra essere una violazione del principio di sostituzione di Liskov. Il che significa che dovresti ripensare il tuo design.

Inoltre anziché B che eredita da A. È possibile che si desideri una classe di base Q da cui derivano sia A che B. [1]

[1] Q è uno scherzo, alcuni studiosi di bibbia pensano che ci sia un libro comune che non è stato detto che chiamano Q da cui ogni vangelo è copiato.

Modifica: aggiuntiva.

Con l'esempio alcune cose sono più chiare. Consentitemi di apportare alcune correzioni di base alla vostra comprensione del C++. Hai detto, hai diversi metodi di creazione statici a causa di conflitti tra argomenti. Penso che sia meglio dire che l'overloading non può risolvere i diversi metodi di costruzione. La risposta è molto semplice: espandi il sovraccarico in due modi. Usa enumerazioni o usa le classi. La prima si può vedere in stream chiamando lettura/aggiungere/lettura-scrittura flussi di tipo aggiungendo ios :: ate ecc

Nel tuo caso:

enum BCT {halfLength,fullLength,quarterLength ...}; 

poi fare Banana statico Create (dimensioni del galleggiante , BCT type = fullLength) { switch (type) { case fullLength: return Banana (size); caso halfLength: return Banana (size * 2); trimestre cassa Lunghezza: ritorno Banana (misura * 4); ... }}

la versione alternativa è quella di utilizzare le classi per distinguere i tipi di parametri (credo James Coplien chiamato questi esemplari)

class FullLength 
class HalfLength 
class QuarterLength 

Poi:

static Banana Create(float length); // Full length 
static Banana Create(float halfLength, HalfLength &dummy); 
static Banana Create(float quarterlength, QuarterLength &dummy); 

Il nuovo le classi non aggiungono nulla al sovraccarico, ma rimuovono l'ambiguità di sovraccarico. Credo che boost/std :: filesystem usi in questo modo per i suoi iteratori di directort.

Detto questo, una volta deciso come creare istanze, questi non devono essere membri statici. Possono essere costruttori ordinari e questo risolverà il tuo problema. Per la maggior parte. Non sarai ancora in grado di impedire ad AdvancedBanana di implementare un metodo di creazione a metà lunghezza, ma il programmatore saprà che lo sta facendo.

Una breve nota su statica, le funzioni membro statiche sono quelli che non accedono al puntatore questo o ciò che alcuni chiamano lingue , cioè non accedere ai membri di una particolare istanza. Infatti, in preC++ 98 giorni, prima che avessero statici, ciò che le persone facevano era di fare qualcosa di simile: ((Banana *)NULL)->static_function(arguments);

Nel tuo esempio, è meglio usare i costruttori in primo luogo. i costruttori statici sono meglio lasciati per cose come le fabbriche dove sono veramente necessarie.

Inoltre, nella risposta di Mido la linea: a.CreateByHalfLength(1); può o non può compilare, io uso tante tante lingue, a volte mi confondo da ciò che è illegale :(ma è mostra pensiero cattivo Il modo corretto per chiamare una statica sarebbe. essere Banana :: CreateByHalfLength (1), non a seconda un'istanza

1

È possibile farlo solo in questo modo, utilizzando eredita privata per AdvancedBanana.

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 

    static Banana CreateByHalfLength(float halfLength) { 
     return Banana(halfLength * 2); 
    } 
}; 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b; 
    b.CreateByHalfLength(1); 

    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 

AdvancedBanana :: CreateByHalfLength dovrebbe esistere, se si desidera che Banana :: CreateByHalfLength esista e sia accessibile dall'esterno della classe. E anche questa non è una buona soluzione.

In un altro modo, mi viene suggerito di progettare due o più classi o di estrarre le funzioni da Banana, per la vostra richiesta. Sarà qualcosa di simile.

#include <stdio.h> 

struct Banana { 
    float length; 

    Banana() {} 

    Banana(float length) { 
     this->length = length; 
    } 
}; 

static Banana CreateByHalfLength(float halfLength) { 
    return Banana(halfLength * 2); 
} 

struct AdvancedBanana : private Banana { 
    float bendAmt; 

    AdvancedBanana(float length, float bendAmt) { 
     this->length = length; this->bendAmt = bendAmt; 
    } 
}; 


int main() 
{ 
    Banana b = CreateByHalfLength(1); 
    AdvancedBanana bb(1, 2); 
    //bb.CreateByHalfLength(2); 

    return 0; 
} 
1

Se si desidera limitare automaticamente le classi derivate sovraccaricare il static Banana CreateByHalfLength(float halfLength); quindi un modo molto veloce è quello di incapsulare quella funzione all'interno di un metodo virtual final.

ad es.

struct Banana { 
    ... 
    // Create a namesake wrapper for the `static` function and make it final 
    virtual 
    Banana CreateByHalfLength(float halfLength) final { 
    return CreateByHalfLengthImpl(halfLength); 
    } 

    static Banana CreateByHalfLengthImpl(float halfLength) { 
    return Banana(halfLength * 2); 
    } 
}; 

Con questa disposizione, ora qualsiasi classe derivata non saranno in grado di creare una funzione simile static o non static.
Here is a demo.

Lo svantaggio di questo approccio è che si aggiunge una funzione di overhead di virtual oltre a essere chiamata con un oggetto non utilizzato.

Problemi correlati