2010-09-29 11 views
5

Ho una semplice classe base C++, esempio di classe derivata.ereditarietà C++, metodi di base nascosti

// Base.hpp 
#pragma once 

class Base 
{ 
public: 
    virtual float getData(); 
    virtual void setData(float a, float b); 
    virtual void setData(float d); 

protected: 
    float data; 
}; 

//Base.cpp 
#include "stdafx.h" 
#include "Base.hpp" 

float Base::getData() 
{ 
    return data; 
} 

void Base::setData(float a, float b) 
{ 
    setData(a); 
} 

void Base::setData(float d) 
{ 
    data = d; 
} 

//Derived.hpp 
#pragma once 
#include "Base.hpp" 

class Derived 
    : public Base 
{ 
public: 
    virtual void setData(float d); 
}; 

//Derived.cpp 
#include "stdafx.h" 
#include "Derived.hpp" 

void Derived::setData(float d) 
{ 
    data = d + 10.0f; 
} 

Se ora faccio un puntatore alla Base questo compila bene.

//Main.cpp 
#include "stdafx.h" 
#include "Base.hpp" 
#include "Derived.hpp" 

Base *obj = new Derived(); 

Ma se faccio un puntatore alla classe derivata, quindi il compilatore (VC 2008 e il 2010) lamenta che:

Main.cpp(12): error C2660: 'Derived::setData' : function does not take 2 arguments 

E qui è il codice che causa questo errore:

//Main.cpp 
#include "stdafx.h" 
#include "Base.hpp" 
#include "Derived.hpp" 

Derived *obj = new Derived(); 

Sembra che i metodi della classe base vengano nascosti. Avevo l'impressione che dal momento che i metodi della classe base sono virtuali, dovrebbero essere visibili anche se visualizzati dal puntatore Derivato, o sbaglio?

+0

Che aspetto ha la classe derivata? –

+1

possibile duplicato di [Sovrascrivere la funzione sovraccaricata di una base in C++] (http://stackoverflow.com/questions/888235/overriding-a-bases-overloaded-function-in-c) –

risposta

11

Questo è un artefatto della ricerca del nome in C++. L'algoritmo di base è che il compilatore inizierà dal tipo del valore corrente e proseguirà la gerarchia finché non troverà un membro sul tipo che ha il nome di destinazione. Quindi eseguirà la risoluzione di sovraccarico solo sui membri di quel tipo con il nome specificato. Non considera i membri con lo stesso nome sui tipi principali.

Il modo per ovviare a questo è quello di ridefinire le funzioni Derived e solo li in avanti fino a Base

class Derived { 
    ... 
    void setData(float a, float b); 
} 

void Derived::setData(float a, float b) { 
    Base::setData(a,b); 
} 

Inoltre è possibile portare i membri di base in ambito utilizzando il using dichiarazione

class Derived { 
    using Base::setData; 
    ... 
} 

Documentazione su questo utilizzo dell'uso

+1

Forse potresti aggiungere un suggerimento a '? – sbi

+0

@sbi, buona chiamata. Aggiunto – JaredPar

+0

@Jerry, grazie risolto – JaredPar

3

Una funzione in una classe derivata nasconderà qualsiasi funzione con lo stesso nome in una classe base.

Se si vuole veramente la funzione di classe di base (s) di questo nome per essere visibile, è possibile aggiungere una dichiarazione secondo per farlo accadere:

class Base { 
public: 
    void setData(float d); 
    void setData(float d, float e); 
}; 

class Derived : public Base { 

    using Base::setData; 

    void SetData(float d); 
}; 

[Revised:] Sembra che la mia memoria era sbagliato. Ciò non causa ambiguità - anche con la dichiarazione using, Derived::setData ha la precedenza (per così dire) così quando invochi setData(float) su un oggetto derivato, ottieni Derived::setData(float). Se lo rendi virtuale e invochi tramite un puntatore su Base, ottieni sempre Derived::setData(float);.

+0

Sì, questa è la strada da percorrere, '+ 1' da me (anche se Jared ha spiegato le ragioni in modo più approfondito). – sbi

Problemi correlati