вызывать версию функции childs вместо родителей? - PullRequest
8 голосов
/ 13 апреля 2011

Ладно, у меня два класса.

class a{
public:
a(){};
void print(){cout << "hello"};
}

class b : public a{
public:
void print(){cout << "hello world";}
}

И множество родителей с ребенком

a blah[10];
blah[5] = b();

Чем я звоню в печать, и хочу, чтобы она поздоровалась с миром.

blah[5].print();

Но это называет родителя. Как мне это исправить?

Ответы [ 4 ]

11 голосов
/ 13 апреля 2011

Это можно исправить, объявив виртуальную функцию, а именно:

class a{
public:
    virtual void print(){
        cout << "hello";
    }
}

class b : public a{
public:
    virtual void print() {
        cout << "hello world";
    }
}

Так реализуется полиморфизм в C ++.Подробнее здесь: http://en.wikipedia.org/wiki/Virtual_function

Однако следует отметить, что в вашем примере она никогда не вызовет дочернюю функцию, потому что вы используете объект значения , а не указатели / ссылки на объекты,Чтобы исправить это,

a * blah[10];
blah[5] = new b();

Затем:

blah[5]->print();
3 голосов
/ 13 апреля 2011

Что вам нужно, так это полиморфизм во время выполнения, который означает, что объект должен принимать «много форм» (т.е. a или b) и действовать соответствующим образом во время работы программы.В C ++ вы делаете это, делая функцию virtual в базовом классе a:

virtual void print() {cout << "hello"}; 

Затем вам нужно хранить элементы по указателю или по ссылке, и - как в общем случае производнуюклассы могут вводить новые члены данных и им нужно больше памяти - это нормально для создания объектов в куче с помощью new:

a* blah[10];
blah[5] = new b();

Затем вы можете вызвать:

blah[5]->print();  

И этовызовет b реализацию print().

Вы должны позже delete blah[5] (и любые другие, на которые вы указали в памяти, возвращается new).

На практике,Хорошая идея - использовать контейнер, который может удалять содержащиеся в нем объекты, когда он сам разрушается, либо из-за выхода из области видимости, либо из-за удаления.std::vector<> является одним из таких контейнеров.Вы также можете использовать смарт-указатели для автоматизации удаления объектов a и b.Это помогает сделать код корректным, если перед выполнением ваших операторов delete создаются исключения, и вы хотите, чтобы ваша программа продолжала работать без утечки памяти.Библиотека boost - самое простое / лучшее место для реализации интеллектуальных указателей.Вместе:

#include <vector>
#include <boost/shared_ptr.hpp>

std::vector<boost::shared_pointer<a> > blah(10);

blah[5] = new b();

(более нормально использовать векторы с push_back(), поскольку он автоматически увеличивает вектор, чтобы соответствовать всем добавленным элементам, с новым общим количеством, доступным по вызову vector::size().)

0 голосов
/ 13 апреля 2011

Это происходит потому, что вы сказали компилятору, что ваш экземпляр имеет тип a.Это в массиве a объектов, верно?Так что он имеет тип a!

Конечно, вы хотите, чтобы метод в b перезаписывал метод в a, несмотря на наличие ссылки на родительский тип.Вы можете получить такое поведение, используя ключевое слово virutal в объявлении функции в родительском классе.

virtual void print(){cout << "hello"};

Почему это так работает?

Потому что, когда выприведя свой объект к родительскому классу, вы внесли неоднозначность.Когда этот объект называется print(), как мы должны относиться к нему?Он имеет тип b, но ссылка относится к типу a, поэтому окружающий код может ожидать, что он будет вести себя как a, а не b!

Чтобы устранить неоднозначность, virtualключевое слово введено.virtual функции всегда переопределяются, если объект принадлежит дочернему классу, содержащему метод с такой же сигнатурой.

Cheers!

0 голосов
/ 13 апреля 2011

Объявите a::print() как виртуальный и используйте указатель / ссылку для вызова функции print(). Когда вы делаете blah[5] = b(), он выполняет нарезку объектов. Вы не имеете никакого эффекта, вызывая виртуальную функцию, используя объект.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...