2010-05-11 3 views
0

Я немного запутался:C++ Typing и OOP дочерние классы

  • Если у меня есть базовый класс A и класс B, который простирается, может переменная типа А хранящие значения из типа B и наоборот?

Если да, то почему? Разве они не совсем разные, даже если B получен из A? Как насчет безопасности типа?

  • Если это возможно, что мне нужно учитывать при использовании этого? Как это сработает с точки зрения производительности?

Примечание: К сожалению, если я спросил слишком много вопросов, просто игнорировать их и просто смотреть на тех, кто «с пометкой» с списком украшением точки :) Кроме того, это не мое домашнее задание. Я программист по хобби и имею навыки написания сценариев с ООП, но я относительно новичок в написании ООП на C++.

+0

Возможно, в качестве примера можно привести код :) –

+1

Почему? Сейчас у меня нет конкретных примеров. Правило о том, что дочерние классы «имеют тот же тип, что и« их классы отца », должны быть общими или? – Zack

+0

Не имея конкретных примеров, почему вы в замешательстве. Код что-то, и это поможет вам разобраться во всем. – jmucchiello

ответ

3

Если вы сделаете это:

B b; 
A a = b; 

, то вы получите "дележ". a будет содержать только A часть b.

Но вы можете иметь ссылки/указатели:

B b; 
A &ra = b; 
A *pa = &b; 

В этом случае ra и pa просто см/точку реального B объекта. Это связано с тем, что публичное наследование моделирует отношение IS-A. Это легче понять с помощью более описательных имен. Подумайте о A и Animal и B как Baboon. A Baboon IS-A Animal поэтому, используя ссылки/указатели, вы можете обработать Baboon, поскольку он более общий тип Animal.

+0

Не могли бы вы объяснить, как и почему это работает с указателями? Почему C++ не кричит о типичной ошибке? Я имею в виду A! = B, или? – Zack

+1

'A' и' B' являются типами, а не объектами (в отличие от многих других языков, где типы являются объектами). С указателями «A *» может ссылаться на все, что происходит от A, и виртуальные функции будут правильно перенаправлены на реализацию производного класса. Например. «Животное» животное = новый Бабуин(); animal-> Eat(); animal-> Sleep(); 'будут называть методы Eat и Sleep класса Baboon, если они виртуальны (в Animal) и переопределены в Baboon. OTOH, если вы сделали «Animal a = Baboon();», будет создан Baboon, но затем * нарезанный *, и вы останетесь с действительным Animal, который не содержит ничего лишнего от Baboon. –

0

Переменная типа A может содержать значение типа B (для определенных определений «удержание», как объясняют другие ответы), но определенно не наоборот. Для того, чтобы выйти стандартный пример:

class Animal {}; 
class Dog : public Animal {}; 
class Cat : public Animal {}; 

Это является законным, так как Cat происходит от Animal:

Cat c; 
Animal& a = c; 

Это не так:

Animal a; 
Cat& c = a; 

Это типобезопасным потому что вы он определил это так; вся цель наследования заключается в том, чтобы разрешить такую ​​вещь, чтобы вы могли перейти к методам вызова на общей переменной Animal, не зная, какой базовый класс будет храниться в ней. Что касается вопроса о производительности, вызов виртуальных методов происходит медленнее, потому что решение о том, какой метод будет фактически вызван (Cat::foo() против Dog::foo(), например, в зависимости от конкретного типа Animal, хранящегося в переменной) должно произойти во время выполнения - это динамическая отправка.С невиртуальными методами решение может произойти во время компиляции

+1

В C++ переменная, которую вы назначаете, должна быть ссылкой (ваш код будет компилироваться, но он не будет работать, как вы ожидаете). Код должен быть «Cat c; Animal & a = c; 'и' Animal a; Cat & c = a; '. См. Другие ответы. –

+0

Это может быть законным, но это не очень полезно. Как сказал Кен, используйте ссылки (или указатели). – jmucchiello

0

указателя или опорной на объект класса A может указывать/ссылаться на объект класса B. Это потому, что если B происходит от A, то Bis-aA. Каждый объект класса B имеет все переменные-члены и функции класса A, а также те, которые уникальны для B.

class A 
{ 
    public: 
     virtual ~A(); 
     void foo(); 
}; 

class B : public A 
{ 
    public: 
     void bar(); 
}; 

A * a = new B; 
a->foo(); // perfectly valid, B inherits foo() from A 
//a->bar(); // compile-time error, bar() is only defined in B 
delete a; // make sure A has a virtual destructor! 

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

0

Не быть противоположным, но производительность здесь не является правильным вопросом. Если вы решили, что собираетесь сделать дизайн OO, не жертвуйте правильной абстракцией для проблем с производительностью. Преждевременная оптимизация - это корень всего зла. Удачи!

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