Форум программистов, компьютерный форум CyberForum.ru

Абстрактный класс чисел - C++

Восстановить пароль Регистрация
 
Рейтинг: Рейтинг темы: голосов - 9, средняя оценка - 4.89
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
27.07.2011, 22:32     Абстрактный класс чисел #1
Нужно создать абстрактный класс чисел с виртуальными методами - арифметическими операциями. У этого класса 2 наследника - комплексные числа и дроби.

Я написал решение этой задачи, но оно мне кажется. Скажите, есть ли другие способы и как можно было сделать это лучше.

Вот мой код:

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
#include <iostream>
#include <string>
#include <math.h>
const double EPS = 1e-4;
using namespace std;
 
void divide(_int64 &a, _int64 &b){
    _int64 i = 2;
    do
        if(a%i == 0 && b%i == 0){
            a /= i;
            b /= i;
        }
        else
            i++;
    while(i <= a && i <= b);
};
 
class Number{
public:
    virtual ostream& print(ostream& st) const = 0;
    virtual void sum(Number& a) = 0;
};
 
class Fraction: public Number{
private:
    int chisl, znam;
public:
    Fraction(int a = 0, int b = 1);
    double get_value() {return 1.0*chisl/znam;};
    ostream& print(ostream& st) const ;
    void sum(Number& a);
};
Fraction::Fraction(int a, int b){
    _int64 a2 = a*abs(b)/b;
    _int64 b2 = abs(b);
 
    divide(a2, b2);
 
    chisl = a2;
    znam = b2;
};
ostream& Fraction::print(ostream &st) const {
    return (st << chisl << "/" << znam);
};
void Fraction::sum(Number& a){
    Fraction arg = (Fraction&) a;
    _int64 com_znam = znam * arg.znam;
    _int64 res_chisl = chisl*arg.znam + arg.chisl*znam;
 
    divide(res_chisl, com_znam);
    chisl = res_chisl;
    znam = com_znam;
};
 
class Complex: public Number{
private:
    double Re, Im;
public:
    Complex(double a = 0, double b = 0): Re(a), Im(b) {};
    double get_real() {return Re;};
    double get_im() {return Im;};
    ostream& print(ostream& st) const ;
    void sum(Number& a);
};
ostream& Complex::print(ostream &st) const {
    if(abs(Re) >= EPS){
        st << Re;
        double Im_abs = abs(Im);
        if(Im_abs >= EPS){
            if(Im > 0)
                st << "+";
            else
                st << "-";
            if(abs(Im_abs -1) >= EPS)
                st << Im_abs;
            st << "i";
        }
    }
    else
        st << Im << "i";
    return st;
};
 
void Complex::sum(Number& a){
    Re += ((Complex&) a).Re;
    Im += ((Complex&) a).Im;
}
 
inline ostream& operator << (ostream& st, Number& val){
    return val.print(st);
};
 
int main(){
    Number* ac = new Complex(-10, 2.5);
    Number* bc = new Complex(18, -6.5);
 
    ac->sum(*bc);
    cout << *ac << endl;
 
    Number* af = new Fraction(7, 30);
    Number* bf = new Fraction(3, 70);
 
    af->sum(*bf);
    cout << *af << endl;
 
    cin.get();
    return 0;
}
После регистрации реклама в сообщениях будет скрыта и будут доступны все возможности форума.
Jupiter
Каратель
Эксперт C++
6542 / 3962 / 226
Регистрация: 26.03.2010
Сообщений: 9,273
Записей в блоге: 1
Завершенные тесты: 2
27.07.2011, 22:45     Абстрактный класс чисел #2
Цитата Сообщение от Ale-X91 Посмотреть сообщение
Я написал решение этой задачи, но оно мне кажется.
что кажется? креститься надо
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
27.07.2011, 22:50  [ТС]     Абстрактный класс чисел #3
Я хотел написать, что оно кажется не совсем удачным.
Слово пропустил, пичалько

Добавлено через 13 секунд
так как решение то?
LosAngeles
Заблокирован
28.07.2011, 07:21     Абстрактный класс чисел #4
где
operator+
operator-
и прочие?
кроме того во fraction надо добавить opeartor double() для неявных пребразований, явно понадобится

Добавлено через 1 минуту
Цитата Сообщение от Ale-X91 Посмотреть сообщение
inline ostream& operator << (ostream& st, Number& val){
return val.print(st);
};
вроде как при выводе val не изменяется, можно сделать константным
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
28.07.2011, 14:55  [ТС]     Абстрактный класс чисел #5
Я сейчас внес небольшие изменения: перегрузил сложение, поменял метод sum (теперь он возвращает ссылку на временный объект). Но когда этот временный объект удалять? И как сделать присваивание?

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
#include <iostream>
#include <string>
#include <math.h>
const double EPS = 1e-4;
using namespace std;
 
void divide(_int64 &a, _int64 &b){
    _int64 i = 2;
    do
        if(a%i == 0 && b%i == 0){
            a /= i;
            b /= i;
        }
        else
            i++;
    while(i <= a && i <= b);
};
 
class Number{
public:
    virtual ostream& print(ostream& st) const = 0;
    virtual Number& sum(Number& a) = 0;
};
 
class Fraction: public Number{
private:
    int chisl, znam;
public:
    Fraction(int a = 0, int b = 1);
    double get_value() {return 1.0*chisl/znam;};
    ostream& print(ostream& st) const ;
    Number& sum(Number& a);
};
Fraction::Fraction(int a, int b){
    _int64 a2 = a*abs(b)/b;
    _int64 b2 = abs(b);
 
    divide(a2, b2);
 
    chisl = a2;
    znam = b2;
};
ostream& Fraction::print(ostream &st) const {
    return (st << chisl << "/" << znam);
};
Number& Fraction::sum(Number& a){
    Number* temp = new Fraction(); // Временный объект. Возвращается ссылка на него
    Fraction arg = (Fraction&) a; //Аргумент
    
    _int64 com_znam = znam * arg.znam;//Общий знаменатель
    _int64 res_chisl = chisl*arg.znam + arg.chisl*znam;//Числитель результата
    divide(res_chisl, com_znam); //Сокращение дроби
 
    ((Fraction*)temp)->chisl = res_chisl;
    ((Fraction*)temp)->znam = com_znam;
 
    return *temp;
};
 
class Complex: public Number{
private:
    double Re, Im;
public:
    Complex(double a = 0, double b = 0): Re(a), Im(b) {};
    double get_real() {return Re;};
    double get_im() {return Im;};
    ostream& print(ostream& st) const ;
    Number& sum(Number& a);
};
ostream& Complex::print(ostream &st) const {
    if(abs(Re) >= EPS){
        st << Re;
        double Im_abs = abs(Im);
        if(Im_abs >= EPS){
            if(Im > 0)
                st << "+";
            else
                st << "-";
            if(abs(Im_abs -1) >= EPS)
                st << Im_abs;
            st << "i";
        }
    }
    else
        st << Im << "i";
    return st;
};
 
Number& Complex::sum(Number& a){
    Number* temp = new Complex();
    ((Complex*)temp)->Re = this->Re + ((Complex&) a).Re;
    ((Complex*)temp)->Im = this->Im + ((Complex&) a).Im;
    return *temp;
}
 
inline ostream& operator << (ostream& st, const Number& val){
    return val.print(st);
};
 
inline Number& operator+(Number& a, Number& b){
    return a.sum(b);
};
int main(){
    Number* ac = new Complex(-10, 2.5);
    Number* bc = new Complex(18, -6.5);
 
    Number& res_c = ac->sum(*bc);
    cout << res_c << endl;
 
    Complex val1(12, 13);
    Complex val2(5, 6);
    cout << val1 + val2 << endl;
 
    cin.get();
    return 0;
}
LosAngeles
Заблокирован
28.07.2011, 15:12     Абстрактный класс чисел #6
так нельзя делать
Цитата Сообщение от Ale-X91 Посмотреть сообщение
Number& Fraction::sum(Number& a){
Number* temp = new Fraction();
Цитата Сообщение от Ale-X91 Посмотреть сообщение
return *temp;
отвественность за удаление лежит на пользователе, плохой стиль

Добавлено через 4 минуты
в явном операторе присваивания нет нужды в твоём случае. Компилятор сгенерирует по умолчанию. В С++11 можно будет явно указывать
C++
1
2
Fraction& operator=(Fraction const&) = default;
Fraction() = delete;
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
28.07.2011, 17:58  [ТС]     Абстрактный класс чисел #7
Понятно ,что плохой. А как тогда сделать, чтобы были определены виртуальные методы и были перегружены операции?

Добавлено через 5 минут
И чтоб работало не только в 11 студии, т.к. у меня 2008, а подобную задачу я видел в книге, где автор пишет, что все проги работают в 2003.NET
CAHTEXHUK
Заблокирован
28.07.2011, 19:01     Абстрактный класс чисел #8
не надо new, просто создай локальный объект и возвращай по значению
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
28.07.2011, 19:30  [ТС]     Абстрактный класс чисел #9
Результат типа Number нельзя по значению передавать, т.к. он абстрактный, и объекты такого типа создавать запрещено. Если поменять тип возвращаемого значения (в одном случае Complex, в другом Fraction), то методы sum перестанут работать как виртуальные. В этом и проблема.
CAHTEXHUK
Заблокирован
28.07.2011, 20:08     Абстрактный класс чисел #10
Цитата Сообщение от Ale-X91 Посмотреть сообщение
Если поменять тип возвращаемого значения
ну естественно так и надо сделать тогда этот страх и ужас сам исчезнет
C++
1
2
((Complex*)temp)->Re = this->Re + ((Complex&) a).Re;
        ((Complex*)temp)->Im = this->Im + ((Complex&) a).Im;
Ale-X91
2 / 2 / 0
Регистрация: 27.07.2011
Сообщений: 12
28.07.2011, 22:21  [ТС]     Абстрактный класс чисел #11
Если поменять тип возвращаемого значения, то методы перестанут работать как виртуальные из-за несоответствия прототипов. А по заданию они должны быть виртуальными. Также типом возвращаемого значения не может быть абстрактный класс, ибо объекты абстрактного класса создавать НЕЛЬЗЯ.
LosAngeles
Заблокирован
29.07.2011, 05:55     Абстрактный класс чисел #12
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
inline Complex operator+(Complex& a, Complex& b){
        Complex *tmp = (Complex*)&a.sum((Number&)b);
        Complex tmp_ret(*tmp);
        delete tmp;
        return tmp_ret;
};
 
int main(){
        Complex* ac = new Complex(-10, 2.5);
        Complex* bc = new Complex(18, -6.5);
 
        Complex res_c = *ac + *bc;
        cout << res_c << endl;
 
        Complex val1(12, 13);
        Complex val2(5, 6);
        cout << val1 + val2 << endl;
 
        cin.get();
        return 0;
}
Добавлено через 1 минуту
operator+ тут как обёртка вокруг sum, снимает с пользователя ответственность за удаление

Добавлено через 3 минуты
sum наверно надо сделать приватным, чтоб им нельзя было воспользоваться, а opeartor+ подружить с Complex
ValeryLaptev
Эксперт C++
1004 / 783 / 46
Регистрация: 30.04.2011
Сообщений: 1,595
29.07.2011, 09:28     Абстрактный класс чисел #13
Цель данного упражнения - чтобы студент покопался с чистыми виртуальными функциями.
Действительно, в лоб реализовать операцию сложения - не проходит из-за абстрактности.
Удивительно, что рядом лежит виртуализованная операция вывода, а виртуализовать аналогично операцию сложения почему-то в голову не приходит...

В классе Fraction надо реализовать приватный метод НОД - наибольший общий делитель. И его потом использовать для сокращения.
MoreAnswers
Эксперт
37091 / 29110 / 5898
Регистрация: 17.06.2006
Сообщений: 43,301
29.07.2011, 09:34     Абстрактный класс чисел
Еще ссылки по теме:

C++ Абстрактный класс
C++ абстрактный класс
Абстрактный класс/Класс интерфейс C++

Искать еще темы с ответами

Или воспользуйтесь поиском по форуму:
LosAngeles
Заблокирован
29.07.2011, 09:34     Абстрактный класс чисел #14
вот кстати более универсальный универсальный подход, подойдёт и для Fraction заодно
C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
template <typename T>
inline T operator+(T& a, T& b){
        T *tmp = (T*)&a.sum((Number&)b);
        T tmp_ret(*tmp);
        delete tmp;
        return tmp_ret;
};
 
int main(){
        Complex* ac = new Complex(-10, 2.5);
        Complex* bc = new Complex(18, -6.5);
 
        Fraction fr1(1, 2);
        Fraction fr2(1, 3);
 
        Fraction fr3(fr1 + fr2);
 
        Complex res_c = *ac + *bc;
        cout << res_c << endl;
 
        Complex val1(12, 13);
        Complex val2(5, 6);
        cout << val1 + val2 << endl;
 
        cin.get();
        return 0;
}
Yandex
Объявления
29.07.2011, 09:34     Абстрактный класс чисел
Ответ Создать тему
Опции темы

Текущее время: 23:07. Часовой пояс GMT +3.
КиберФорум - форум программистов, компьютерный форум, программирование
Powered by vBulletin® Version 3.8.9
Copyright ©2000 - 2016, vBulletin Solutions, Inc.
Рейтинг@Mail.ru