2013-11-06 6 views
1

Предположим, у нас есть два класса: Base и Derived. Существует два метода: getX и setX, которые являются общедоступными и используют защищенный int x для взаимодействия с пользователем. Base конструкторы x к 1, и Derived строительные наборы х до 3.Производная переменная класса C++

class Base { 
public: 
    Base(); 
    int getX(); 
    void setX(int n); 
protected: 
    int x; 
} 

int Base::getX() { 
    return x; 
} 

void Base::setX(int n) { 
    x = n; 
} 

Base::Base() : x(1) { 
} 

class Derived : public Base { 
public: 
    Derived(); 
} 

Derived::Derived() : x(3) { 
} 

Derived класс имеет полный доступ к методам из базы. Отлично.

Предположим, что по какой-то причине я не хочу, чтобы setX был доступен для пользователей класса Derived. Есть несколько способов, которые я думал об этом.

1) Redeclare setX как закрытый в Derived, поэтому затенение не позволяет пользователю полностью получить доступ к этому методу.

2) Redeclare x как частный const int in Derived. Однако это приводит к тому, что setX и getX работают с Base :: x.

3) Сделать базой :: setX виртуальной функцией, создать функцию Derived :: setX, которая ничего не делает.

Каков наилучший способ справиться с этим?

+0

вы должны создать конструктор 'Base (int n)', тогда вы можете сделать 'Derived :: Derived(): Base (3) {}', как это теперь, ваш код не компилируется. –

+0

Если вы используете метод 1, можно получить доступ к скрытой функции подробным образом: 'Derived d; d.Base :: SetX (9); '- эта возможность, желательная для вашего дизайна, или вы хотите ее предотвратить? – anatolyg

ответ

5

Как Derived Публично полученное от Base, то, что вы пытаетесь сделать, не имеет большого смысла. Вместо этого вы должны использовать private или protected наследование, а затем предоставить доступ в Derived только к методам от Base, которые вам нужны, а не наоборот.

+0

Я получаю конфиденциально только в том случае, если некоторые виртуальные функции необходимо переопределить. Иначе я бы сочинил. –

0

Вы не можете инициализировать элемент x в списке инициализаторе Derived, поскольку x не является членом Derived. Ваш компилятор должен выпустить ошибку.

1

Вы не переопределяете какие-либо виртуальные функции, поэтому наследование сомнительно.

Вы хотите, чтобы пользователи использовали интерфейс Base или интерфейс Derived? Если вы скажете Derived, снова это сомнительно.

Compose Derived из Base и дать ему лучшее название:

class Composite { 
private: 
    Base base; 
public: 
    Composite() : base(3) { 
    } 
}; 
2

Во-первых, как заметил anatolyg, слежка setX метод в 1), сделав его рядовым в Derived классе не мешает кому-то назвать его на класс Base непосредственно путем литья.

Итак, 1) это нормально, если вы принимаете это.

В противном случае, если вы хотите, чтобы обеспечить реализацию setX в Base классе ко многим производным классом, но без публичного либо Base или производный класс пользователя. просто сделайте setX метод защищен в Base класс. В этом случае вы, вероятно, также можете сделать x private и вызвать метод setX от конструктора Derived.

Если вы хотите запретить пользователю любой экземпляр класса Derived вызвать метод setX на этом объекте ... но все еще иметь его в интерфейсе, очевидно, что вы могли бы, как вы предложили в 3) сделать его виртуальным в Base и реализовать его в Derived.

Но в этом случае вы идете против девиза наследования «есть» (очевидно, ваш производный класс не ведет себя как базовый класс).

Если то, что вы ищете это ошибка компиляции, чтобы запретить этот вызов, может быть, вы могли бы пересмотреть свою иерархию:

  • class real_Base;, который не реализует setX метод
  • class Base : public real_Base; который реализует setX метод
  • class Derived : public real_Base;, который не использует setX

В этом случае, то:

  • вы будете использовать real_Base как интерфейс, когда ваш код клиента не нужно вызывать setX.
  • использование Base когда вызов setX допускается
  • использовать Derived когда вызов setX запрещено.
Смежные вопросы