2010-04-14 2 views
4

Я нашел этот код hereкласс, который не может быть получен

class Usable; 

class Usable_lock { 
    friend class Usable; 
private: 
    Usable_lock() {} 
    Usable_lock(const Usable_lock&) {} 
}; 

class Usable : public virtual Usable_lock { 
    // ... 
public: 
    Usable(); 
    Usable(char*); 
    // ... 
}; 

Usable a; 

class DD : public Usable { }; 

DD dd; // error: DD::DD() cannot access 
     // Usable_lock::Usable_lock(): private member 

Может кто-нибудь объяснить мне этот код?

EDIT: Еще один вопрос, который у меня есть, является тем, что является виртуальным деривацией и когда это необходимо?

+2

Обратите внимание, что этот класс не выполняет то, что он говорит на олове, - это не предотвращает вывод. Если бы это произошло, получилось бы сообщение об ошибке в точке, на которой фактически получен класс. – 2010-04-14 12:39:13

+0

Это статья о виртуальном наследовании: http://en.wikipedia.org/wiki/Virtual_inheritance. Почему виртуальное наследование используется здесь? Чтобы предотвратить множественные проблемы наследования, когда класс Usable получен из какого-либо другого класса, кроме Usable_lock. –

+0

Попробуйте изменить эту ссылку вместо этого: http://www2.research.att.com/~bs/bs_faq2.html#no-derivation «Он полагается на то, что самый производный класс в иерархии должен построить виртуальная база ". Класс DD делает это. –

ответ

5

Это свойство virtual происхождения.

Идея virtual вывода заключается в решении «Ужасное ромба»:

struct Base {}; 

struct D1: Base {}; 
struct D2: Base {}; 

struct TopDiamond: D1, D2 {}; 

Проблема здесь состоит в том, что TopDiamond имеет 2 экземпляра Base здесь.

Чтобы решить эту проблему, очень своеобразное «MultiInheritance», C++ использует ключевое слово virtual и то, что называется так называемым «виртуальным наследованием».

Если мы изменим путь D1 и D2 определены таким образом, что:

struct D1: virtual Base {}; 
struct D2: virtual Base {}; 

Тогда будет только один экземпляр Base в TopDiamond: работу фактически инстанцировании он остается в топ-конструктор (здесь TopDiamond).

Таким образом, маленькая хитрость, вы показали, объясняется просто здесь:

  • потому что Usable происходит практически с Usable_lock, это до его производного класса для конкретизации Usable_lock части объекта
  • потому Usable_lock конструктора являюсь private, только сам и Usable (друг) могут получить доступ к конструктору

это умное, я никогда не думал об этом. Интересно, какая стоимость virtual наследования здесь (дополнительная память/скорость накладных расходов)?

+0

Yup, это суммирует это довольно хорошо. Я потратил немного меньше времени на объяснение того, что виртуальное наследование, как правило, полезно, но тогда я должен был лениться написать ответ сам. ':)' +1 от меня. – sbi

1

класс Usable_lock «s Конструктор объявляется под Private Так что не доступен за пределами

Usable_lock class 

когда вы делаете объект

DD dd; 

Он будет вызывать конструктор Usable и Usable_Lock как (потому что DD, полученные от Usable и Usable Производные от Usable_lock)

и, следовательно, он не может получить доступ к Constructor Usable_Lock в .. и это даст вам ошибки

+0

Однако 'class Usable' является другом и поэтому должен иметь к нему доступ. 'DD' не должен иметь доступ к' Usable_lock', это '' Usable''s job (?). –

+2

@Pasi: 'Usable_lock' - это« виртуальная »база, поэтому производные классы должны иметь доступ к одному из своих конструкторов. К сожалению, ответ mihirpmehta не упоминает об этом. – sbi

+0

@sbi да очень верно ... я не смог упомянуть об этом ... ( –

1

Есть две точки здесь:

1) Почему Полезный экземпляр может быть создан, если он включает в себя частный конструктор Usable_lock ? Потому что Usable является другом Usable_lock.

2) Почему экземпляр, основанный на использовании, не может быть создан? Потому что он включает частный конструктор Usable_lock.

+1

Подсказка - это о 'виртуальном' деривации. –

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