C ++ Typing и OOP дочерние классы - PullRequest
0 голосов
/ 12 мая 2010

Я немного запутался:

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

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

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

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

Ответы [ 4 ]

3 голосов
/ 12 мая 2010

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

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 голосов
/ 12 мая 2010

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

0 голосов
/ 12 мая 2010

A указатель или ссылка на объект класса A может указывать / ссылаться на объект класса B. Это потому, что если B происходит от A, то B is-a A. Каждый объект класса 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 голосов
/ 12 мая 2010

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

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, хранящегося в переменной), должно выполняться при запуске -time - это называется динамическая отправка . С не виртуальными методами решение может произойти во время компиляции

...