Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Вопрос

8.1K
31 июля 2006 года
Нео
48 / / 30.07.2006
class aaa
{
.....
};

class bbb:public aaa
{
public:
void save();
};

aaa *ggg()
{
bbb *d=new bbb;
return d;
}

void main()
{
aaa *c=ggg();
// <= Надо вызвать save()
}

ВОПРОС: как из переменной c вызвать save() ?
Если написать c->save(), то так не получится, т.к. это функция класса-потомка.
3
31 июля 2006 года
Green
4.8K / / 20.01.2000
Используй виртуальные методы:
Код:
class aaa
{
public:
    virtual void save() =0;  // в данном случае абстрактный метод, но можно и с реализацией.
};

class bbb :public aaa
{
public:
    virtual void save();
};

aaa* ggg()
{
    bbb *d=new bbb;
    return d;
}

void main()
{
    aaa* c=ggg();
    c->save();
}
4.5K
31 июля 2006 года
e-XperT
127 / / 04.07.2006
По-моему в коде ошибка: в функция ggg() должна вернуть указатель на объект класса ааа, а мы возвращаем указатель на объект класса bbb. Т.о пользователь функции ggg() присваивая объекту класса ааа результат действия функции ожидает, что после вызова метода save() будет выполнен метод aaa::save(), а выполняется в данном случае bbb:save().
3
31 июля 2006 года
Green
4.8K / / 20.01.2000
Все нормально. Читаем про наследование, виртуальные методы и абстрактные классы.
562
03 августа 2006 года
tarekon
175 / / 19.08.2003
Еще можно так:
((bbb*)c)->save();
однако в этом случае если в с окажется действительно ааа, то выйдет ошибка времени исполнения. Использование виртуальных функций в этом смысле надежнее, но лишает нас счастья иметь объект класса ааа. Выбирай сам, что в твоем случае лучше.
3
03 августа 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=tarekon] Использование виртуальных функций в этом смысле надежнее, но лишает нас счастья иметь объект класса ааа.[/QUOTE]
Это ещё почему?!
Реализуй метод в aaa и имей счастье.
562
02 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]Это ещё почему?!
Реализуй метод в aaa и имей счастье.[/QUOTE]
Пардон, но метод был объявлен как чисто виртуальный. Даже если я его реализую, объект класса я создать не смогу.
3
02 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=tarekon]Пардон, но метод был объявлен как чисто виртуальный. Даже если я его реализую, объект класса я создать не смогу.[/QUOTE]
Если ты реализуешь метод, то он уже не будет чисто виртуальным.
Соотв-но и объявлять его надо будет уже не чистовиртуальным.
562
03 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]Если ты реализуешь метод, то он уже не будет чисто виртуальным.
Соотв-но и объявлять его надо будет уже не чистовиртуальным.[/QUOTE]
Неверно. Реализовать можно даже чисто виртуальный метод.
3
03 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=tarekon]Неверно. Реализовать можно даже чисто виртуальный метод.[/QUOTE]
Вот это новости!
Ну как пример в студию!
562
04 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]Вот это новости!
Ну как пример в студию![/QUOTE]
Это не новости, это внимательное чтение стандарта.
Код:
class A {
public:
   virtual void f() = 0;
};

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

void A::f()
{
   cout << "Call";
}

void B::f()
{
   cout << "Function";
   A::f();
}

void main()
{
   A* ex = new B;
   ex->f();
   delete ex;
}

Компилится и работает. По крайней мере, на MS VC 2003. На других компиляторах тоже должно.
3
04 сентября 2006 года
Green
4.8K / / 20.01.2000
Да, действительно, в стандарте есть буквально одно предложение об этом
(Лично мне, не понятно, для чего нужно было такое нелогичное отступление в стандарте. Может кто объяснит?):
Цитата:

10.4.2
A pure virtual function need be defined only if explicitly called with the qualified-id syntax (5.1).


Но! Это не имеет никакого отношения к данной теме, т.к. при вызове "with the qualified-id syntax" ни о каком полиморфизме не может быть речи. Надеюсь, это всем понятно. Тема же была именно про полиморфизм.

Использование виртуальных функций НЕ лишает нас "счастья иметь объект класса ааа", как ты неверно утверждал.
Чтоб не лить дальше воду, просто привожу код:

Код:
class aaa
{
public:
    virtual void save();
};

class bbb :public aaa
{
public:
    virtual void save();
};

void main()
{
    aaa a;  // можем создавать объекты и класса aaa
    bbb b;  // и класса bbb
   
    aaa* p = &b;
    p->save();    // полиморфизм в действии
}


P.S. Просьба, в следующий раз, когда ссылаетесь на стандарт, давать выдержку из него с указанием параграфа.
Кстати, по стандарту функция main возвращает значение int, а не void.
562
04 сентября 2006 года
tarekon
175 / / 19.08.2003
Тогда пойдем по порядку.
Изначально вопрос был в том, как вызвать метод save из класса bbb, если есть экземпляр класса aaa, в котором эта функция не определена.
Ты предложил метод с использованием чисто виртуальных функций, я сказал, что тогда нельзя создавать объект класса aaa.
Теперь ты предложил использовать обычные виртуальные функции, но тогда требуется определить функцию save в классе aaa, что противоречит условию задачи.
Либо у нас разные понимания этого самого условия...
3
04 сентября 2006 года
Green
4.8K / / 20.01.2000
Я не вижу противоречия "условию задачи", если мы реализуем виртуальную функцию в родительском классе. Если в родительском классе эта функция ничего делать не должна, то делаем её реализацию пустой. Я не вижу тут сложностей.
562
04 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]Я не вижу противоречия "условию задачи", если мы реализуем виртуальную функцию в родительском классе. Если в родительском классе эта функция ничего делать не должна, то делаем её реализацию пустой. Я не вижу тут сложностей.[/QUOTE]
Всё ясно. Просто у нас разный подход. Я не люблю (и пока вроде ни разу не делал) функций с пустой реализацией. На мой взгляд, этот подход для снятия ошибок линковки "некрасив" и означает неправильное построение архитектуры. Поэтому для меня использование здесь виртуальных фукнций означает именно использование чисто виртуальных. Ладно, всё это нюансы восприятия информации, а не языка С++. Думаю, теперь можно закрывать этот тред.
3
04 сентября 2006 года
Green
4.8K / / 20.01.2000
С точки зрения архитектуры такой подход (с пустой реализацией) вполне верен, т.к. если мы хотим создавать объект базового класса, логично предположить, что у него должны быть реализованы все методы общего интерфейса.
Если же какой-то из методов чисто абстрактный, то это значит, что класс является абстрактным, т.е. экземпляра такого класса не может существовать в принципе (например COM-интерфейс), а сл-но он и не может и не должен создаваться. Так что это не ограничение использования абстрактных классов, а их прямое назначение - не давать возможности создать свои экземпляры.
562
04 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]С точки зрения архитектуры такой подход (с пустой реализацией) вполне верен, т.к. если мы хотим создавать объект базового класса, логично предположить, что у него должны быть реализованы все методы общего интерфейса.
Если же какой-то из методов чисто абстрактный, то это значит, что класс является абстрактным, т.е. экземпляра такого класса не может существовать в принципе (например COM-интерфейс), а сл-но он и не может и не должен создаваться. Так что это не ограничение использования абстрактных классов, а их прямое назначение - не давать возможности создать свои экземпляры.[/QUOTE]
Со вторым абзацем я не спорю. Но первый мне все равно не нравится. Хотя бы генерирование исключения туда засунуть. А то получится код, маскирующий ошибку. Ну да черт с ним.
[QUOTE=Green]Но! Это не имеет никакого отношения к данной теме, т.к. при вызове "with the qualified-id syntax" ни о каком полиморфизме не может быть речи. Надеюсь, это всем понятно. Тема же была именно про полиморфизм.[/QUOTE]
Можно её вызвать и без qualified-id, виртуально. Не стал приводить такой пример. Он бы тоже отношения к теме не имел :)
3
04 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=tarekon]Со вторым абзацем я не спорю. Но первый мне все равно не нравится. Хотя бы генерирование исключения туда засунуть. А то получится код, маскирующий ошибку. Ну да черт с ним.
[/QUOTE]
Не... не черт с ним. :)
У нас конструктивный диалог получается, так что давай продолжим.

Засунуть туда assert можно, но зачем?
В случае не с абстрактным классом у нас получается полноценный класс, который имеет некоторый общий со своими потомками интерфейс и который может иметь свои экземпляры. Сл-но, и вполне рабочий метод у него должен быть. А не делается в этом методе ничего потому, что делать нечего. Похоже на то, как всем присылают письмо из пенсионного фонда. Кто-то, кто продвинутый, реализует его, кладет деньги в банки. А вот я прото игнорирую. :)

[QUOTE=tarekon]
Можно её вызвать и без qualified-id, виртуально. Не стал приводить такой пример. Он бы тоже отношения к теме не имел :)[/QUOTE]
Хм... Не могу представить как. Да и это, кажется, противоречит выдержке из стандарта (см. выше).
Покажи как, если это возможно.
562
06 сентября 2006 года
tarekon
175 / / 19.08.2003
[QUOTE=Green]Не... не черт с ним. :)
У нас конструктивный диалог получается, так что давай продолжим.

Засунуть туда assert можно, но зачем?
В случае не с абстрактным классом у нас получается полноценный класс, который имеет некоторый общий со своими потомками интерфейс и который может иметь свои экземпляры. Сл-но, и вполне рабочий метод у него должен быть. А не делается в этом методе ничего потому, что делать нечего. Похоже на то, как всем присылают письмо из пенсионного фонда. Кто-то, кто продвинутый, реализует его, кладет деньги в банки. А вот я прото игнорирую. :)[/QUOTE]
У меня немного другое видение всего этого. Изначально в базовом классе не было такой функции, она появилась только для того, чтобы в производном классе было её удобно вызывать (именно удобно, так как способ с вирт. функциями не единственный). Поэтому эта функция никогда не должна вызываться. Собственно ислючение нужно, чтобы отловить ошибку в программе.
По аналогии с письмами - если ко мне придет письмо, адресованное, допустим, ВВП, с печатью американского посольства, то я, скорее всего, не буду его игнорировать :)
[QUOTE=Green]
Хм... Не могу представить как. Да и это, кажется, противоречит выдержке из стандарта (см. выше).
Покажи как, если это возможно.[/QUOTE]
Противоречит. Но в стандарте иногда встречаются вещи, нереализуемые в жизни. Тот же export для шаблонов.
Сия ошибка (часто сопровождаемая сообщением "pure virtual method call") происходит, когда кто-нибудь пытается задействовать механизм виртуальных вызовов для неполностью сконструированного объекта. Такое можно сделать, например, в конструкторе базового класса. Разные компиляторы используют разные подходы для обнаружения и предотвращения такого рода ошибок, но программисты все равно хитрее и умудряются в них вляпаться :). Так, MSVC сообщает об этом, если вызов происходит непосредственно в конструкторе. Однако если вызов вытащить во внешнюю функцию, вызываемую из конструктора, то можно торжественно нарваться на мину. Кстати, у ребят из 1С уже был опыт с этим - половина запросов к Яндексу со строкой "pure virtual method call" выдает описание бага одного из их продуктов.
Собственно, код:
Код:
#include <iostream>

class Base;
void g( Base* );

class Base {
public:
    Base() { g( this ); }
    virtual void f() = 0;
};

class Derived : public Base {
public:
    void f();
};

void Derived::f()
{
    std::cout << "Hello, world!\n";
}

void g( Base* p )
{
    p->f();
}

int main()
{
    Derived A;
    return 0;
}

Опять-таки, другие компиляторы могут отловить и этот трюк. Тогда можно попробовать вынести определение функции g в другой файл. Собственно, всё.
3
06 сентября 2006 года
Green
4.8K / / 20.01.2000
[QUOTE=tarekon]У меня немного другое видение всего этого. Изначально в базовом классе не было такой функции, она появилась только для того, чтобы в производном классе было её удобно вызывать (именно удобно, так как способ с вирт. функциями не единственный).
[/QUOTE]
Ну теперь уже я буду говорить, что это баг в архитектуре. :)

[QUOTE=tarekon]
Сия ошибка (часто сопровождаемая сообщением "pure virtual method call") происходит, когда кто-нибудь пытается задействовать механизм виртуальных вызовов для неполностью сконструированного объекта.
<skip>
[/QUOTE]
На счет этого я в курсе.
Я понял из предыдущего поста, что тебе известен механизм позволяющий именно вызвать реализованный pure virtual метод Base::f() не через qualified-id. Т.е. не получить "pure virtual method call", а именно выполнить реализацию этого метода.
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог