2016-11-15 4 views
2

Я не понимаю следующее ограничение:Использование частного абстрактного метода в производном классе

class Base 
{  
    virtual doFoo() = 0; 
}; 

class Derived : public Base 
{ 
public: 
    void doStuff() { doFoo(); } //compile error, doFoo is a private member of Base  
}; 

Решение, конечно, повторно объявить элемент в производном классе, но это кажется несколько странным для меня:

class Derived : public Base 
{ 
public: 
    void doStuff() { doFoo(); } 

private: 
    virtual doFoo() = 0; 
}; 

Почему я не могу использовать абстрактный виртуальный частный метод базового класса в производном классе без повторного объявления его? Это кажется чрезмерно жестким ограничением, потому что, если бы я использовал его, но не определил его, то Derived все еще является абстрактным и для его создания некоторый дополнительный производный класс должен был бы предоставить doFoo.

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

+2

Почему бы не использовать 'protected'? Я, вероятно, что-то пропустил –

+1

Это основы инкапсуляции. Частный частный, вот и все.Если вы как разработчик классов хотите выставить что-то в подклассы, используйте protected, и если вы хотите подвергать свою функциональность всем клиентам (и подклассам в этом случае), используйте public. –

+0

IMHO, частный виртуальный метод, не имеет большого смысла. Виртуальные средства, которые могут быть переопределены подклассами, а частные средства недоступны из базовых классов ... Вы имеете в виду защищенный вместо этого? –

ответ

3

Функции частного базового класса не могут быть вызваны непосредственно в методах производного класса. Однако эта недоступность по производному классу не имеет ничего общего с механизмом виртуального вызова, который относится к производному классу.

Есть случаи, когда это желательно. Взято с C++ FAQ.

Вы могли бы спросить: что хорошего в методе, который производный класс не может назвать? Несмотря на то, что производный класс не может вызвать его в базовом классе, базовый класс может вызвать его, который эффективно вызывает класс (соответствующий). И вот в чем заключается шаблон шаблона.

Подумайте о «Назад в будущее». Предположим, что базовый класс написан в прошлом году, и вы собираетесь сегодня создать новый производный класс. Методы базового класса, которые могли быть скомпилированы и застряли в библиотеке несколько месяцев назад, будут вызывать частный (или защищенный) виртуальный, и это будет эффективно «звонить в будущее» - код, который был скомпилирован несколько месяцев назад, вызовет код который еще не существует - код, который вы собираетесь написать в ближайшие несколько минут. Вы не можете получить доступ к частным членам базового класса - вы не можете дойти до прошлого, но прошлое может охватить будущее и вызвать ваши методы, которые вы еще не написали.

+0

Так что, по сути, эта ссылка говорит далее «Копировать код». Я могу жить с обновлением, но мне было действительно интересно, была ли еще одна важная причина, почему это не работает прямо из коробки (например, компилятор вставляет чистые виртуальные повторные объявления самостоятельно, если это им необходимо). – Resurrection

2

Объявление новой функции-члена в производном классе не дает вам доступа к одному с тем же именем в базовом классе. Тот, который находится в базовом классе, по-прежнему является закрытым, и вы не можете получить доступ к нему извне базового класса (отсутствующие объявления друзей). Это не имеет ничего общего с тем, что функция-член является чистой виртуальной; это относится ко всем именам. Если вы не хотите, чтобы он был закрытым, не определяйте его как конфиденциальный.

0

Если вы хотите получить доступ к этому методу из производного класса, хорошим подходом является его объявление protected.

Здесь, даже если вы не объявляете метод как private, доступ по умолчанию class равен private. Это означает, что вы неявно объявляете этот метод как private.

(Если бы вы использовали struct вместо доступа по умолчанию был бы public.)

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