2016-10-30 2 views
1

Допустим, у меня есть базовый класс с защищаемого элемента:доступ к защищенным членам существующего базового объекта

class Base 
{ 
public: 
    Base(int data) 
    : m_attribute(data) {} 

protected: 
    int m_attribute; 
}; 

и производный класс из базы:

class Derived : public Base 
{ 
public: 
    int get_attribute() 
    { 
     return m_attribute; 
    } 
}; 

Прежде всего: я могу это сделать , правильно? Является ли это полностью законным?

Если да, то вот вопрос:

  • Я ничего не могу в классе Base изменить;
  • У меня есть объект класса Base, и мне нужно получить доступ к его члену m_attribute;

Должен ли я сначала отключить этот объект базового класса до производного класса, а затем вызвать функцию get_attribute()? Что-то вроде этого:

Base base(5); 
Derived* derived = static_cast < Derived*>(&base); 
int base_attribute = derived->get_attribute(); 

Или какие другие способы доступа к защищенному члену? Я знаю, что функция друга является опцией, но я не могу ничего изменить в базовом классе

+0

Первого вопрос: Да, вы можете, чтобы ваши мечты сбылись – Treycos

+0

статичные литое ничего не делают – Treycos

+1

Возможной дубликаты [Почему я не могу получить доступ к защищенный член из экземпляра производного класса?] (http://stackoverflow.com/questions/967352/why-cant-i-access-a-protected-member-from-an-instance-of-a-der ived-class) –

ответ

3

Должен ли я сначала сбрасывать этот объект базового класса на производный объект класса, а затем вызывать функцию get_attribute()?

Определенно нет. Экземпляр базового класса не является экземпляром производного класса. Ваше преобразование плохо сформировано.

Вот действительный путь:

struct kludge : Base { 
    kludge(const Base& b): Base(b) {} 
    operator int() { 
     return m_attribute; 
    } 
}; 

использование:

Base base(5); 
int foo = kludge(base); 

Этот ляп работает копия построения базового суб объекта производного типа. Это, конечно же, зависит от того, какая база может быть скопирована - это ваш Base. Легко настроить и работу с подвижным.

В качестве синтаксического сахара kludge неявно конвертируется в тип элемента. Если вы предпочитаете, вы можете использовать геттер.

+0

Его очень специфический пример использования. Что делать, если мой базовый класс очень сложный, который имеет множество параметров и не так легко сконструирован? –

+0

@AlexShirokov до тех пор, пока база является скопируемой (или подвижной с небольшим изменением в kludge), сложность конструкции основания также не имеет никакого эффекта. – user2079303

+0

Хорошо, а как насчет оператора в()? Будет ли доступ к m_attribute в регулярной функции-члене? –

-1

Класс Derived может получить доступ и изменить свойства и методы базового класса public и protected.

Тогда вы не можете использовать базу в производном. Производный унаследовать от базы, поэтому Derived - это база. Но база не является производным (автомобиль - это автомобиль, автомобиль не автомобиль).

Так что, если вам нужен геттер, поместите его прямо в базу или создайте производное вместо базы.

+0

Я ничего не могу изменить в базовом классе, thats probelm –

-1

Во-первых:

Derived* derived = static_cast < Base*>(base); 

Это не является действительным и незаконным. Не компилируется. Вы не можете статическим отливом Base до Base*.

И ответить на ваш вопрос:

Base base(5); 
Derived& derived = static_cast<Derived&>(base); 
std::cout << derived.get_attribute(); 

Или, если вы хотите использовать указатель, потому что вы думаете, что вы круче:

Base base(5); 
Derived* derived = static_cast<Derived*>(&base); 
std::cout << derived->get_attribute(); 

EDIT: static_cast не имеет какого-либо накладные расходы во время выполнения. Это статические, следовательно, это компиляция. Оба метода дадут тот же результат.

+0

Кстати, избегайте использования необработанных указателей :) – Treycos

+0

Какая операция будет быстрее? Кастинг на ссылку или указатель? –

+0

@AlexShirokov Я отредактировал ответ. – DeiDei

0

Если базовый класс не имеет конструктора по умолчанию после перегрузки, чтобы принять некоторые аргументы и не существует по умолчанию, то производные классы должны использовать список-инициализатор-член для инициализации базовой части, иначе вы не сможете создать производный класс, получая компилятор жалуется на отсутствующие конструктор по умолчанию в базовом классе:

class Base 
{ 
    public: 
    // Base(){} default constructor by default the compiler creates one for you unless you overload it so the next one taking one parameter will hide this one 
     Base(int data) // hides the default ctor so derived classes must use member-initializer list 
     : m_attribute(data) {} 

    protected: 
     int m_attribute; 
}; 


class Derived : public Base 
{ 
    public: 
     Derived() : Base(0){} // you must use member intializer list to initialize the part Base 
     //Derived(int x) : Base(x){} // also ok 
     int get_attribute(){ return m_attribute; } 
}; 

int main() 
{ 
    Derived dervObj; 

    Derived* derived = static_cast < Derived*>(&baseObj); 
    int base_attribute = derived->get_attribute(); 
    cout << base_attribute << endl; 

} 
  • также вы не можете бросить адрес класса базы производной объекта, но отбрасывать объект базового класса производной один.

так в вашем примере писать в основной:

Derived* derived = static_cast < Derived*>(&baseObj); // is like writing: 
char* cp = static_cast < char*>(&int); // you must convert a variable not a type 
  • почему вы хотите получить доступ к защищенным членам снаружи ??? имейте в виду, что публичное наследование скопирует всех членов базы в производный класс, но будет закрыто.

  • , используя дружбу или публикуя данные о членах общественности, позволит получить доступ к ней извне, но это подрывает принципы скрытия данных и инкапсуляции, однако дружба в некоторых случаях является обязательной, и нет другой альтернативы, но используйте ее осторожно, но обнародование данных это лучше, чтобы вернуться на структуры

Смежные вопросы