Il termine "interfaccia" in C ++

11

Java distingue chiaramente class e interface . (Credo che anche C # lo faccia, ma non ne ho esperienza). Tuttavia, quando si scrive C ++ non esiste una distinzione applicata tra linguaggio e classe.

Di conseguenza ho sempre considerato l'interfaccia come soluzione alternativa alla mancanza di ereditarietà multipla in Java. Fare una tale distinzione è arbitrario e privo di significato in C ++.

Ho sempre avuto la tendenza ad adottare l'approccio "scrivi le cose nel modo più ovvio", quindi se in C ++ ho quello che potrebbe essere chiamato un'interfaccia in Java, ad esempio:

class Foo {
public:
  virtual void doStuff() = 0;
  ~Foo() = 0;
};

e ho quindi deciso che molti implementatori di Foo volevano condividere alcune funzionalità comuni che probabilmente scriverei:

class Foo {
public:
  virtual void doStuff() = 0;
  ~Foo() {}
protected:
  // If it needs this to do its thing:
  int internalHelperThing(int);
  // Or if it doesn't need the this pointer:
  static int someOtherHelper(int);
};

Che quindi non rende più questa interfaccia in senso Java.

Invece il C ++ ha due concetti importanti, relativi allo stesso problema di ereditarietà sottostante:

  1. virtual inhertiance
  2. Le classi senza variabili membro non possono occupare spazio extra se usate come base

    "Base class subobjects may have zero size"

    Riferimento

Di quelli che cerco di evitare il numero 1 ovunque sia possibile - è raro imbattersi in uno scenario in cui questo è veramente il design "più pulito". # 2 è comunque una sottile, ma importante differenza tra la mia comprensione del termine "interfaccia" e le caratteristiche del linguaggio C ++. Come risultato di ciò, attualmente (quasi) non mi riferisco mai a cose come "interfacce" in C ++ e parlo in termini di classi base e loro dimensioni. Direi che nel contesto di C ++ "l'interfaccia" è un termine improprio.

Ho notato che non molte persone fanno una tale distinzione.

  1. Sono disposto a perdere qualcosa consentendo l'esistenza di funzioni non- protected (ad esempio virtual ) all'interno di una "interfaccia" in C ++? (La mia sensazione è esattamente l'opposto - una posizione più naturale per il codice condiviso)
  2. Il termine "interfaccia" è significativo in C ++ - implica solo solo % virtual o sarebbe corretto chiamare le classi C ++ senza alcuna variabile membro ancora un'interfaccia?
posta Flexo 13.02.2012 - 11:14
fonte

4 risposte

11

In C ++, il termine "interfaccia" non ha solo una una definizione ampiamente accettata, quindi ogni volta che la utilizzerai, dovresti dire cosa intendi esattamente - una classe base virtuale con o senza implementazioni predefinite, un file di intestazione, i membri pubblici di una classe arbitraria e così via.

Riguardo al tuo esempio: in Java (e simili in C #), il tuo codice probabilmente implicherebbe una separazione di preoccupazioni:

interface IFoo {/*  ... */} // here is your interface

class FooBase implements IFoo 
{
     // make default implementations for interface methods
}

class Foo extends FooBase
{
}

In C ++, puoi fare questo, ma non sei obbligato a farlo. E se ti piace chiamare un'interfaccia di classe se non ha variabili membro, ma contiene implementazioni predefinite per alcuni metodi, fallo semplicemente, ma assicurati che tutti quelli con cui stai parlando sappiano cosa intendi.

    
risposta data 13.02.2012 - 11:52
fonte
7

Sembra un po 'come se tu fossi caduto nella trappola di confondere il significato di ciò che un'interfaccia è concettualmente sia come un'implementazione (l'interfaccia -' i 'minuscola), sia un'astrazione (Un'interfaccia - maiuscola 'IO').

Riguardo ai tuoi esempi, il tuo primo pezzetto di codice è semplicemente una classe. Mentre la tua classe ha un'interfaccia nel senso che fornisce metodi per abilitare gli accessi al suo comportamento, non è un'interfaccia nel senso di una dichiarazione di interfaccia che fornisce un livello di astrazione che rappresenta un tipo di comportamento che è possibile che le classi implementino. La risposta di Doc Brown sul tuo post ti mostra esattamente di cosa sto parlando qui.

Le interfacce sono spesso propagandate come "work-around" per le lingue che non supportano l'ereditarietà multipla, ma ritengo che sia più di un malinteso che di una dura verità (e ho il sospetto che potrei essere fiammeggiato per averlo detto!) . Le interfacce non hanno davvero nulla a che fare con l'ereditarietà multipla in quanto non richiedono né l'ereditarietà né l'antenato per fornire la compatibilità funzionale tra le classi o l'astrazione di implementazione per le classi. In effetti, possono permetterti di eliminare completamente l'ereditarietà nel caso in cui desideri implementare il tuo codice in quel modo - non che lo consiglierei interamente, ma sto solo dicendo che potresti fare esso. Quindi la realtà è che indipendentemente dalle questioni di ereditarietà, le interfacce forniscono un mezzo attraverso il quale possono essere definiti i tipi di classe, stabilendo le regole che determinano come gli oggetti possono comunicare tra loro, quindi consentono di determinare il comportamento che le classi dovrebbero supportare senza dettare il metodo specifico utilizzato per implementare tale comportamento.

Do I stand to lose anything by allowing (e.g. protected) non-virtual functions to exist within an "interface" in C++? (My feeling is the exactly the opposite - a more natural location for shared code)

Una pura interfaccia è pensata per essere completamente astratta, perché consente la definizione di un contratto di compatibilità tra classi che non necessariamente hanno ereditato il loro comportamento da un antenato comune. Una volta implementato, si desidera scegliere se consentire l'estensione del comportamento di implementazione in una sottoclasse. Se i tuoi metodi non sono virtual , perdi la possibilità di estendere tale comportamento in un secondo momento se dovessi decidere di creare classi discendenti. Indipendentemente dal fatto che l'implementazione sia virtuale o meno, l'interfaccia definisce la compatibilità comportamentale in sé e per sé, mentre la classe fornisce l'implementazione di tale comportamento per le istanze rappresentate dalla classe.

Is the term "interface" meaningful in C++ - does it imply only pure virtual or would it be fair to call C++ classes with no member variables an interface still?

Perdonami, ma è passato molto tempo da quando ho davvero scritto una seria applicazione in C ++. Ricordo che Interface è una parola chiave ai fini dell'astrazione come li ho descritti qui. Non chiamerei le classi C ++ di qualsiasi tipo di interfaccia, direi invece che la classe ha un'interfaccia all'interno dei significati che ho delineato sopra. In questo senso il termine è significativo, ma dipende molto dal contesto.

    
risposta data 13.02.2012 - 12:37
fonte
6

Le interfacce Java non sono una "soluzione alternativa", sono una decisione progettuale intenzionale per evitare alcuni dei problemi con ereditarietà multipla come l'ereditarietà del diamante e per incoraggiare pratiche di progettazione che riducano al minimo l'accoppiamento.

La tua interfaccia con metodi protetti è un caso da manuale che ha bisogno di "preferire la composizione sull'ereditarietà". Per citare Sutter e Alexandrescu nella sezione con quel nome dai loro eccellenti standard di codifica C ++ :

Avoid inheritance taxes: Inheritance is the second-tightest coupling relationship in C++, second only to friendship. Tight coupling is undesirable and should be avoided where possible. Therefore, prefer composition to inheritance unless you know that the latter truly benefits your design.

Includendo le tue funzioni di supporto nell'interfaccia, potresti risparmiare un po 'di digitazione ora, ma stai introducendo un accoppiamento che ti farà del male lungo la strada. È quasi sempre meglio a lungo termine rendere le tue funzioni di supporto separate e passare in Foo* .

L'STL è un buon esempio di questo. Poiché molte funzioni di supporto possibili vengono estratte in <algorithm> anziché essere nelle classi contenitore. Ad esempio, poiché sort() utilizza l'API del contenitore pubblico per svolgere il proprio lavoro, è possibile implementare il proprio algoritmo di ordinamento senza dover modificare alcun codice STL. Questo design abilita librerie come boost, che migliorano lo STL invece di sostituirlo, senza che l'STL debba sapere nulla di boost.

    
risposta data 13.02.2012 - 17:19
fonte
2

Do I stand to lose anything by allowing (e.g. protected) non-virtual functions to exist within an "interface" in C++? (My feeling is the exactly the opposite - a more natural location for shared code)

Lo penseresti, ma mettere un metodo protetto, non virtuale in una classe altrimenti astratta detta l'implementazione a chiunque scriva una sottoclasse. In questo modo si sconfigge lo scopo di un'interfaccia nel suo senso puro, che è quello di fornire un rivestimento che nasconde ciò che è sotto.

Questo è uno di quei casi in cui non esiste una risposta valida per tutti e devi usare la tua esperienza e il tuo giudizio per prendere una decisione. Se puoi dire con certezza al 100% che ogni possibile sottoclasse della tua classe% -competente completamente Foo avrà sempre bisogno di un'implementazione del metodo protetto bar() , allora Foo è il posto giusto per esso. Una volta che hai una sottoclasse di Baz che non ha bisogno di bar() , devi vivere con il fatto che Baz avrà accesso al codice che non dovrebbe o passerà attraverso l'esercizio della riorganizzazione della gerarchia delle classi. Il primo non è una buona pratica e il secondo può impiegare più tempo dei pochi minuti necessari per sistemare le cose correttamente in primo luogo.

Is the term "interface" meaningful in C++ - does it imply only pure virtual or would it be fair to call C++ classes with no member variables an interface still?

La sezione 10.4 dello standard C ++ fa una breve menzione dell'uso di classi astratte per implementare le interfacce ma non le definisce formalmente. Il termine è significativo in un contesto generale di informatica e chiunque sia competente dovrebbe capire che " Foo è un'interfaccia per (qualunque cosa)" implica una qualche forma di astrazione. Quelli con esposizione a linguaggi con costrutti di interfaccia definiti potrebbero pensare in puro virtuale, ma chiunque abbia bisogno di lavorare effettivamente con Foo esaminerà la sua definizione prima di procedere.

    
risposta data 13.02.2012 - 13:14
fonte

Leggi altre domande sui tag