Компьютерный форум OSzone.net  

Компьютерный форум OSzone.net (http://forum.oszone.net/index.php)
-   Программирование и базы данных (http://forum.oszone.net/forumdisplay.php?f=21)
-   -   [решено] C++: Подскажите, в чем заключается ошибка. (http://forum.oszone.net/showthread.php?t=159387)

Oleg_SK 07-12-2009 02:27 1288300

C++: Подскажите, в чем заключается ошибка.
 
Решил изучить C++. Сейчас разбираюсь с наследованием классов и виртуальными функциями. Слабал простенькую программку:
Код:

//---------------------------------------------------------------------------

#pragma hdrstop
#include <iostream.h>

class Mammal
{
        public:
                Mammal(){cout << "***\n\n";}
                virtual ~Mammal(){}
                virtual void Speak() const {cout << "Mammal speak!\n\n";}

        //protected:
        int z;
};

class Dog : public Mammal
{
        Dog(){}
        virtual ~Dog(){}
        void Speak() const {cout << "Dog speak!\n\n";}
};

class Cat : public Mammal
{
        Cat(){}
        virtual ~Cat(){}
        void Speak() const {cout << "Cat speak!\n\n";}
};
//---------------------------------------------------------------------------

#pragma argsused
int main(int argc, char* argv[])
{
        Mammal * theArray[3];
        Mammal * ptr;
        int choice, i;
        for (i = 0; i < 3; i++) {
                cout << "(1)Dog (2)Cat: ";
                cin >> choice;
                switch (choice)
                {
                        case 1:
                                ptr = new Dog;
                                break;

                        case 2:
                                ptr = new Cat;
                                break;

                        default:
                                ptr = new Mammal;
                                break;
                }

                if (ptr != NULL) {
                        theArray[i] = ptr;
                }
                else
                {
                        cout << "\n\nNULL ptr!!!\n\n";
        }
        }

    cout << "\n\n";
        for (i = 0; i < 3; i++) {
                theArray[i] -> Speak();
        }

        int x;
        cin >> x;
        return 0;
}
//---------------------------------------------------------------------------

Проблема заключается в том, что эта программа не компилируется; компилятор жалуется, что конструкторы классов Dog и Cat недоступны (is not accessible). Если закомментировать эти конструкторы, то прога нормально компилится и работает... Хотелось бы узнать: из-за чего возникла эта ошибка, и как ее исправить?

Oleg_SK 07-12-2009 02:49 1288312

Все, сам разобрался - забыл объявить методы классов Cat и Dog публичными, а по дефолту они являются приватными. Непонятно только почему тогда без проблем вызывался для объектов этих классов метод Speak()? Это связано с его виртуальностью?

Delirium 07-12-2009 03:03 1288316

Цитата:

Цитата Oleg_SK
class Mammal
{
public:
Mammal(){cout << "***\n\n";}
virtual ~Mammal(){}
virtual void Speak() const {cout << "Mammal speak!\n\n";} »

Так выше же написано PUBLIC: и идет перечисление публичных функций, в т.ч. и Speak. Потому и видим.

El Scorpio 07-12-2009 03:16 1288322

Цитата:

Цитата Oleg_SK
Если закомментировать эти конструкторы, то прога нормально компилится и работает... »

Потому что в этом случае компилятор автоматически создаёт конструкторы, которые являются public.

Oleg_SK 07-12-2009 07:17 1288355

Цитата:

Цитата Delirium
Так выше же написано PUBLIC: и идет перечисление публичных функций, в т.ч. и Speak. Потому и видим. »

Непонятка в том, что без проблем вызываются и те виртуальные функции Speak(), которые определены в классах Dog и Cat, а они, из-за допущенной мной ошибки, были там приватными...

Цитата:

Цитата El Scorpio
Потому что в этом случае компилятор автоматически создаёт конструкторы, которые являются public. »

То есть конструкторы и деструктор класса нужно всегда объявлять как публичные методы. Я верно понял? В книге, которую я читаю, об этом прямо не упоминается (по крайней мере, я не помню чтобы там шла об этом речь)...

El Scorpio 08-12-2009 02:03 1289183

Oleg_SK, не содержащие какого-то специфичного кода методы "деструктор", "конструктор по умолчанию", "конструктор копирования" и "оператор присваивания" в C++ объявлять не обязательно - компилятор их создаёт и заполняет стандартным кодом автоматически.

Цитата:

Цитата Oleg_SK
То есть конструкторы и деструктор класса нужно всегда объявлять как публичные методы. »

Нет, не всегда.
Порою вышеперечисленные методы специально объявляют, как private, если хотят запретить данное действие в классе и его потомках. Существование "закрытого" метода в родительском классе не позволяет компилятору генерировать стандартный код в производных объектах. Данное действие будет запрещено до явного объявления открытого метода.
Явный пример - класс TObject из Borland C++ Builder. Объекты, производные от данного абстрактного класса, могут располагаться только в "куче", из-за чего операции создания объекта-копии и присваивания одного объекта другому применимы. По-этому для данного объекта явно указаны private методы TObject (const TObject &) и TObject& operator = (const TObject &).
Далее, для объектов класса TComponent - невидимый компонент экранной формы - и производных от него всегда должно быть определено значение поля "владелец" (Owner). В*результате адрес компонента-владельца указывается, как параметр конструктора, а конструктор по умолчанию TComponent (void) также объявлен "закрытым" (или "защищённым", не помню точно)

А вот результат создания "закрытого" деструктора я предсказать не могу :)

Oleg_SK 09-12-2009 07:22 1290223

Кстати, забыл задать еще один вопрос по терминологии: является ли рекурсией ситуация, когда метод одного объекта класса вызывает себя в контексте другого объекта этого же класса?

Delirium 09-12-2009 07:35 1290226

Самый простой способ ответить на вопрос - поставить точку отладки на начало функции и повызывать метод :) Если будет сам в себя заходить, то рекурсия.
Википедия - рекурсия

Oleg_SK 09-12-2009 08:39 1290250

Вызывать то она себя вызывает. Если бы речь шла об обычной функции, то и вопроса бы не возникло, т.к. это очевидная рекурсия. У меня с этим объектно-ориентированным программированием уже похоже скоро крышу сорвет, т.к. начал сомневаться в обычных вещах. Если не углубляться в реализацию классов, то может создаться впечатление что у каждого объекта класса имеется своя копия набора методов этого класса. Например, есть связанный список, узлами которого являются объекты одного класса. У каждого объекта этого класса есть метод Insert, который, проверив вставляемый в список узел, решает либо самостоятельно вставить этот узел, либо отправляет его дальше по списку, передавая его методу Insert следующего узла списка (так производится сортировка при вставке). В списке есть множество узлов и соответственно множество идентичных по коду методов. Таким образом создается впечатление, что лично себя метод Insert не вызывает, а вызывает свою копию в следующем узле списка, которая в свою очередь может вызвать очередную свою копию в следующем узле списка и т.д. Рекурсия - это ситуация, когда функция вызывает саму себя. В описанном же мной случае, создается впечатление, что есть множество копий одной функции, которые последовательно вызывают друг-друга... Поэтому и возник вопрос: а рекурсия ли это вообще (если не углубляться в реализацию классов компилятором)?

El Scorpio 10-12-2009 02:37 1291165

Цитата:

Цитата Oleg_SK
Если не углубляться в реализацию классов, то может создаться впечатление что у каждого объекта класса имеется своя копия набора методов этого класса. »

Цитата:

Цитата Oleg_SK
В списке есть множество узлов и соответственно множество идентичных по коду методов. Таким образом создается впечатление, что лично себя метод Insert не вызывает, а вызывает свою копию в следующем узле списка, которая в свою очередь может вызвать очередную свою копию в следующем узле списка и т.д. »

Обычный "метод класса" - это обычная функция, которая содержит неявный параметр this (указатель на самого себя). Данный указатель используется для обращения к полям объекта и подставляется в вызовы других методов этого же объекта. А "статичный метод" (static) - это функция без параметра this. Как следствие, из неё можно обращаться только к статичным полям (которые общие для всех объектов данного класса) и вызывать другие статичные методы.

Как следствие, в рассматриваемой ситуации имеем N вложенных (рекурсивных) вызовов функции с разными значениями параметра this


Время: 01:55.

Время: 01:55.
© OSzone.net 2001-