Абстрактные Класс

Тема в разделе "C и С++ FAQ", создана пользователем Vadik(R), 23 фев 2014.

  1. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Здравствуйте, дорогие форумчане.
    Скажу сразу, задание помогаю делать знакомой, и обычно проблем не возникало никаких с её заданиями, но в этот раз.. Я от задания сам стал находится в небольшом шоке.. В общим, хороший такой пробел у меня по абстрактным классам, меня в универе по ним не гоняли ((
    Собственно, проблема такая (выложу пока её часть, по мере решения буду код ещё давать).
    Итак, задание. В него ещё вникал некоторое время:
    Во-первых, для меня было уже откровением, что есть чисто абстрактные методы.
    Немного погуглив, приступил к реализации.
    Вот, что пока вышло.
    Код pair.h:
    Код (C++):
    class Pair
    {
    public:
    Pair();
    ~Pair();
    virtual void read() = 0;
    virtual void write() = 0;
    virtual Pair& operator=(Pair &other) = 0;
    virtual Pair& operator+(Pair &other) = 0;
    };
    Код pair.cpp:
    Код (C++):
    #include "pair.h"

    Pair::Pair()
    {

    }

    Pair::~Pair()
    {

    }
    Код fraction.h:
    Код (C++):
    #include "pair.h"

    class Fraction : public Pair
    {
    public:
    Fraction();
    Fraction(Fraction &other);
    Fraction(long numerator, long denominator);
    ~Fraction();
    void read();
    void write();
    virtual Pair& operator=(Pair &other);
    virtual Pair& operator+(Pair &other);

    protected:
    virtual Pair& operator=(Fraction &other);
    virtual Pair& operator+(Fraction &other);

    private:
    unsigned short denominator;
    long numerator;
    };
    Код fraction.cpp:
    Код (C++):
    #include <iostream>
    #include "fraction.h"

    using namespace std;

    long gcd(long a, long b)
    {
    return b ? gcd(b, a % b) : a;
    }

    void normalize(long &numerator, long &denominator)
    {
    long n;
    if (denominator < 0)
    {
    numerator = -numerator;
    denominator = -denominator;
    }
    if (numerator == 0 || denominator == 0)
    {
    denominator = 1;
    }
    n = gcd(abs(numerator), abs(denominator));
    numerator /= n;
    denominator /= n;
    }

    Fraction::Fraction()
    {
    numerator = 0;
    denominator = 1;
    }

    Fraction::Fraction(Fraction &other)
    {
    this->numerator = other.numerator;
    this->denominator = other.denominator;
    }

    Fraction::Fraction(long numerator, long denominator)
    {
    normalize(numerator, denominator);
    this->numerator = numerator;
    this->denominator = denominator;
    }

    Fraction::~Fraction()
    {

    }

    void Fraction::read()
    {
    cout << "Введите числитель: ";
    cin >> numerator;
    cout << "Введите знаменатель: ";
    cin >> denominator;
    }

    void Fraction::write()
    {
    cout << numerator << " / " << denominator;
    }

    Pair& Fraction::operator=(Pair &other)
    {
    cout << "operator=Pair" << endl;
    *this = *(Fraction*)&other;
    return *this;
    }

    Pair& Fraction::operator+(Pair &other)
    {
    cout << "operator+Pair" << endl;
    //return other + *this; - it doesn't work Oo
    return *(Fraction*)&other + *this;
    }

    Pair& Fraction::operator=(Fraction &other)
    {
    cout << "operator=Fraction" << endl;
    this->numerator = other.numerator;
    this->denominator = other.denominator;
    return *this;
    }

    Pair& Fraction::operator+(Fraction &other)
    {
    cout << "operator+Fraction" << endl;
    //return Fraction(10, 8);
    return *(new Fraction(this->numerator * other.denominator + other.numerator * this->denominator, this->denominator * other.denominator));
    }
    Код main.cpp:
    Код (C++):
    #include <cmath>
    #include <iostream>
    #include <locale>
    #include "fraction.h"

    using namespace std;

    int main()
    {
    Pair* a;
    Pair* b;
    Pair* c;
    cout.setf(ios::fixed);
    cout.precision(2);
    setlocale(LC_ALL, "Rus");
    a = new Fraction();
    a->read();
    b = new Fraction();
    b->read();
    c = new Fraction();
    *c = *a + *b;
    cout << "c = ";
    c->write();
    cout << endl;

    delete a;
    delete b;
    delete c;
    return 0;
    }
    Теперь мои комментарии к коду и вопросы. То, что write - это метод, а не оператор, << пишущий в ostream - опустим, примут, не сложно переделать.
    Насчёт использования
    Код (C++):
    virtual Pair& operator=(Pair &other);
    virtual Pair& operator=(Fraction &other);
    вообще не уверен, просто спустя большое количество просиженных часов, и перепробовав методом перебора кучу способов так, чтобы заработало, как-то сами собой эти строчки у меня получились. Возможно они и не нужны, жду подсказок от гуру, как нужно делать такие задания :)
    Далее, собственно вопросы.
    Наткнулся на такой полезный учебник, который и читал. А именно, вот: http://www.cap-design.ru/ccc/130.htm
    Сделал всё по аналогии, но почему-то у меня не работает участок кода, как у них:
    Код (C++):
    Pair& Fraction::operator+(Pair &other)
    {
    cout << "operator+Pair" << endl;
    //return other + *this; - it doesn't work Oo
    return *(Fraction*) &other + *this;
    }
    Он не подставляет дальше всё (закоменченную строчку) в
    Код (C++):
    Pair& Fraction::operator+(Fraction &other)
    Почему - не в курсе, но он рекурсивно вызывает сам себя и вылетает (для того cout и поставил :))
    Это первый такой, основной вопрос. Я его решил приведением типа (но это же не профессионально, да?)
    Тогда встал второй вопрос.
    Код (C++):
    Pair& Fraction::operator+(Fraction &other)
    {
    cout << "operator+Fraction" << endl;
    //return Fraction(10, 8);
    return *(new Fraction(this->numerator * other.denominator + other.numerator * this->denominator, this->denominator * other.denominator));
    }
    Если я создаю просто объект, то он не всегда корректно потом выводит значения. Было return Fraction(5, 6);, c->write() в коде нормально работал (т. е. всегда писал 5 / 6). А вот на дробь 10 / 8 он почему-то стал выводить совсем другие значения.
    return *new Fraction....
    В общем, возврат значение указателя - в этом случае сложение происходит корректно. Но есть утечка памяти, что есть очень плохо. Проверяется:
    Код (C++):
    for (unsigned int i = 0; i < 10000000; i++)
    {
    *c = *a + *b;
    }
    //для паузы
    a->read();
    Вот в таком случае явно видно, что занятая оперативная память около 400 Мб.

    В общем, любые комментарии, помощь - приветствуются. Мне это важно не только, чтобы знакомой сделать лабу, а чисто для себя.
    В олимпиадном программировании и собственном быдлокодинге абстрактные классы никак мне не пригодились, а вот при устройстве на работу, чувствую, вполне возможны вопросы по абстрактным классам на собеседовании. Заранее всем спасибо :)

    P.S. Для удобства добавил сам проект :) Посмотреть вложение test.rar
     
  2. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    Ну я поясню.
    http://www.cap-design.ru/ccc/130.htm - говносайт, ворующий контент с других сайтов. Ты можешь загуглить первую строку статьи по своей ссылки и убедиться. Но это видно и невооруженным взглядом (на номральных программерских сайтах подстветка кода работает, не работает только на говносайтах типа кодебая {АДМИН, ОБРАТИ ВНИМАНИЕ}). С моего блога тоже воруют статьи, поэтому я негодую, когда ссылаются на воров.

    То что описано в статье - нрмальными людьми называется двойной диспетчеризацией и к твоей задачи отношения не имеет. Там должен быть где-то ранг класса (чтобы программа на падала в твоей рекурсии).

    Потому что оператор не должен использовать new. Никогда. А у тебя использует.

    Добавлено: Почитай на хабре большую статью про операторы- там есть примеры. Вот по ним и решай свою задачу.
     
  3. Vadik(R)

    Vadik(R) Well-Known Member

    Регистрация:
    12 дек 2007
    Сообщения:
    483
    Симпатии:
    0
    Добавил вывод сообщений в конструкторах и деструкторах, и у меня получается так, что если я делаю без new, например, просто даже return Fraction(10, 8); то происходит следующее:
    1. Конструктор Pair
    2. Конструктор Fraction
    3. Деструктор Fraction
    4. Деструктор Pair
    И только потом уже происходит попытка присвоения *c некой "пустоты" (деструктор же всё уничтожил).

    Спасибо, стараюсь дальше решить проблему. Мне бы хотя бы для оператора+ разобраться, дальше по аналогии уже пойму как делать :)
     
  4. rrrFer

    rrrFer Well-Known Member
    Команда форума C\C++ Team

    Регистрация:
    6 сен 2011
    Сообщения:
    1.324
    Симпатии:
    36
    Напиши как ты возвращаешь результат - если по значению - то да - перед возвратом создается временный объект, который уничтожается при выходе из функции (деструктор вызывается, все законно)

    http://stackoverflow.com/questions/1116154...han-two-objects

    посмотри примеры.
     
Загрузка...
Похожие Темы - Абстрактные Класс
  1. BashOrgRu
    Ответов:
    6
    Просмотров:
    4.144
  2. swyatogor
    Ответов:
    0
    Просмотров:
    65
  3. Corexis
    Ответов:
    0
    Просмотров:
    67
  4. rrrFer
    Ответов:
    0
    Просмотров:
    130
  5. Sander
    Ответов:
    1
    Просмотров:
    507

Поделиться этой страницей