2013-07-26 2 views
0

У меня есть абстрактный класс AUnit с переменными и геттерами/сеттерами в виртуальном чистом, как этотC++ защищенного наследия

class AUnit {int var... int getVar() const = 0 ... } 

Всех данные в защищенном: кроме конструктора и деструктора.

У меня есть Берсерк и Танк, как ребенок, как этот

class Berserk : public AUnit 
{ 
... 
private: 
int getVar() const; 

В их .cpp, я пишу код геттеры и сеттеры. Ничего особенного.

Но у меня есть еще один класс (Foo, например), как это

class Foo : public Berserk, public Tank 

, которым необходимо получить доступ к данным в Берсерк или танк, поэтому я изменил частный ключевое слово по защищаемой, здесь ошибка:

Как во-первых, я просто попытался получить доступ к данным с помощью AUnit getter, но стал причиной виртуальных чистых и абстрактных понятий, я думал, что reinterpret_cast мой AUnit в его реальном типе после передачи getType AUnit в нечистых и публичных , Все еще не работает, его схема, о которой я вам говорил ранее.

Это просто классическое наследие, могу ли я помочь?

+0

В классе 'Foo: public Berserk, public Tank'' Я предполагаю, что вы имеете в виду частный, не так ли? – hivert

+0

Можете ли вы «объяснить» немного больше? Я не уверен, что понимаю ваш «вопрос» и ваше видение проблемы. – Khelben

+0

Звучит как [алмаз смерти] (http://en.wikipedia.org/wiki/Multiple_inheritance#The_diamond_problem) для меня. – reima

ответ

0

Как правило, плохой идеей является предоставление более строгой функции защиты, чем функция, которую она переопределяет. Рассмотрим:

class Base { 
public: 
    virtual void f() {} 
}; 

class Derived : public Base { 
private: 
    virtual void f() {} // overrides Base::f 
}; 

Derived d; 
d.f(); // error - f is private 
Base* pb = &d; 
pb->f(); // OK - calls d.f() 

Чтобы избежать таких парадоксов, разумно поставить переопределение на том же уровне доступа, что и оригинал (или более расслабленном уровне доступа, хотя это несколько необычно).

1

Ваш код, отрезанный, конечно, не завершен. Я предполагаю, что у вас есть что-то вроде этого:

int Foo::f(Tank const* tank) { 
    return tank->getY(); 
} 

(возможно, вы делаете что-то более интересное со значением, чем возвращаете его).

Даже если доступ к Tank::getY() является protected, класс Foo не будет иметь доступ к getY() в приведенном выше коде, так как объект, на который указывает tank не известно, Foo объект: класс имеет доступ только к protected членов в базовом объекте своего типа! То есть, следующий будет хорошо:

int Foo::f(Foo const* foo) { 
    return foo->getY(); 
} 

До сих пор только хорошее применение я нашел для protected функций а virtual членов, которые имеют достаточную собой нетривиальную реализацию в базовом классе и которые вызываются из [далее] производный класс как часть переопределения члена. Таким образом, можно добавить функциональность и использовать общую логику (конечно, любая функция virtual равна неpublic, а скорее private или protected).

+0

Я ищу исправления благодаря вашему ответу, но у меня есть один глупый вопрос. Если у меня есть Animal, который может быть Cat, так Cat: public Animal. Я не могу использовать Animal как Cat, потому что это не все время, но я могу манипулировать Cat как Animal всегда, так что здесь Foo - это дети Танка, поэтому почему я не могу использовать получателей Tank для манипулирования моим Foo, если они находятся в защищенный? Для моего использования мне не нужен настоящий тип, реферат в порядке. – Khelben

+0

Вы можете сделать это с типом * вашего * типа, то есть 'Foo' в этом случае. Но вы не можете сделать это с объектами, тип которых не является статически известным как 'Foo', но известно только, что это тип' Tank'. То есть доступ 'protected 'предоставляется только членам производного типа для доступа к объектам указанного производного типа. –

+0

Извините, но могу ли я использовать вашу электронную почту для отправки вам моих 3-х классов, чтобы иметь конкретное представление о том, как обрабатывать, чтобы преуспеть в этой части? Трудно объяснить с помощью foo и т. Д. – Khelben

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