modifica del valore di un membro privato di una classe in c ++ senza utilizzare la funzione membro o amico

2

Usando il puntatore, sono in grado di modificare il valore privato della classe nel codice sottostante.

Violare il concetto di C ++ che il membro privato può essere modificato solo dalle funzioni membro o amico?

#include<iostream>
using namespace std;

class demo
{
        private: int info;

        public:
                 demo()
                 {
                         info=10;
                 }

                 void print_info()
                 {
                       cout<<info;
                 }
};

int main()
{

     demo ob;
     int* ptr=(int*)&ob;

     *ptr=20;

     ob.print_info();

     return 0;
}
    
posta curious 09.08.2013 - 09:13
fonte

4 risposte

9

Il meccanismo C ++ di membri pubblici, protetti e privati ha lo scopo di proteggerti da incidenti, non da intenzioni malevole.

Reinterpretare un puntatore come se punti a qualcos'altro (come fai con int* ptr=(int*)&ob ) conta come "intenzioni malevole" e in genere significa che stai oltrepassando il linguaggio C ++. Quello che succede dipende interamente dal compilatore e non deve essere coerente in ciò che fa.

Tieni presente che esistono altri modi per esporre dati privati, ad esempio:

class demo
{
    private: int info;

    public:
             demo()
             {
                     info=10;
             }

             int* expose_info()
             {
                    return &info;
             }
};

Questo è completamente legale in C ++ (sebbene di solito una cattiva idea). Il meccanismo pubblico / protetto / privato funziona solo sui nomi (quindi il nome info non è accessibile agli estranei), ma se riesci a mettere le mani su un puntatore / riferimento a un membro privato, hai pieno accesso a quel membro.

    
risposta data 09.08.2013 - 12:02
fonte
2

I descrittori di accesso in C ++ sono un meccanismo statico . La conformità viene verificata in fase di compilazione dal compilatore e nessuna memoria del livello di privacy dei metodi o degli attributi viene conservata in fase di esecuzione, né vengono eseguiti controlli a tale data.

Usando un cast in stile C stai completamente aggirando i controlli statici di C ++ e tutte le scommesse sono disattivate.

    
risposta data 09.08.2013 - 15:33
fonte
1

Il codice pubblicato esatto ha definito il comportamento in c ++ 11, dal momento che demo è una classe di layout standard e le informazioni (il membro dati) sono accessibili come un tipo compatibile, ma è di cattivo gusto.

La classe di layout standard deve:

  • Avere lo stesso controllo di accesso per tutti i membri dei dati
  • Non ha funzioni virtuali
  • eredita solo dalle classi di layout standard
  • Al massimo una classe nella sua gerarchia di classi ha i membri dati
  • Non ha membri di dati con lo stesso tipo di quelli nella gerarchia di classi

Questo testo è semplificato dal 9.7 della bozza dello standard. Nella mia terminologia, la gerarchia delle classi include la classe stessa e i membri dei dati coprono solo i membri di dati non statici.

L'accesso al membro dati con un tipo incompatibile causerebbe un comportamento indefinito, come sempre. Ad esempio short non è definito, ma char e int è definito.

In breve, tale accesso è definito se la classe è un layout standard. Quindi sii MOLTO attento. Puoi verificare se un tipo è un layout standard con std :: is_standard_layout

    
risposta data 10.08.2013 - 00:05
fonte
0

Ciò è accaduto accidentalmente per anni tramite buffer overflow, pessimi alias e altri errori del puntatore. Scrivi memoria oltre i limiti di un array e viola! stai corrompendo la memoria (possibilmente privata) in un altro oggetto. Stai usando un puntatore che è stato demarcato altrove, quindi un altro processo crea un oggetto a tale indirizzo e viola !, stai corrompendo la memoria. Le caratteristiche di accessibilità di C ++ servono per scrivere contratti e separare le preoccupazioni nel tuo design per i tuoi utenti. Proprio come in C # e JAVA, non impedisce a nessuno - molto probabilmente a te stesso per errore - di usare in modo errato i puntatori.

Nota a margine, puoi anche usare memcpy per copiare una classe in un'altra usando la stessa identica idea. Non dovresti mai farlo nel codice di produzione, ma può essere fatto facilmente.

    
risposta data 09.08.2013 - 16:51
fonte

Leggi altre domande sui tag