Другое > Hard'n'Soft
Програмирование на C++
HoRRoR:
--- Цитата ---Класс у меня просто Stack ведь называется, зачем тогда придумали дописывать ещё и <T>? Я ведь и так предыдущей строчкой обязан напомнить о шаблоне так зачем же дважды это делать?
--- Конец цитаты ---
Потому что тебе никто не запрещает написать какой угодно другой шаблон для этой функции класса:
--- Код: ---template <>
bool Stack<int>::push(const int &pushValue)
{
cout << "Stack::push() for int called!" << endl;
...
}
template <typename T>
bool Stack<T>::push(const T &pushValue)
{
cout << "Stack::push() for another type called!" << endl;
...
}
--- Конец кода ---
А T писать - потому что класса Stack не существует, существует класс Stack<тип> для каждого из типов, с которыми используется шаблон Stack.
gepar:
А почему нельзя так
--- Код: ---double printArray( const T *array, int count, int low=0, int high=count )
--- Конец кода ---
Count у меня здесь количество элементов в массиве, low - первый элемент который нужно печатать, high - последний элемент который нужно печатать.
И как в таком случае тогда поступать?
Здесь я хочу чтобы на печать отправлялся полностью массив если функции передано два аргумента, и не полностью если 3 или 4 аргумента.
Добавлено позже:
Нет, я конечно могу сделать так чтобы вместо count сразу был high
--- Код: ---double printArray( const T *array, int high, int low=0)
--- Конец кода ---
И это в данном случае подойдёт но мне на будущее, так сказать, хотелось бы знать что делать когда я хочу необязательному аргументу функции присвоить значение обязательного аргумента вот как здесь я писал.
HoRRoR:
--- Цитата ---А почему нельзя так
--- Конец цитаты ---
Потому что спецификация этого не позволяет.
--- Цитата ---И как в таком случае тогда поступать?
--- Конец цитаты ---
Как вариант:
--- Код: ---double printArray( const T *array, int count, int low=0, int high=-1)
{
if(high == -1)
high = count;
...
}
--- Конец кода ---
gepar:
Переделываю старую программу которая была что-то вроде искуственного массива, так вот там раньше была перегрузка в классе объявлена вот так в .h файле:
--- Код: ---const Array &operator=( const Array & ); // assignment operator
--- Конец кода ---
и вот так потом в cpp файле
--- Код: ---const Array &Array::operator=( const Array &right )
--- Конец кода ---
Когда я создал свой шаблон с этим классом для template <typename T> то я теперь не знаю как в cpp файле указать что функция пренадлежит шаблону, я уже и так и эдак, а оно всё равно ошибки сыплет.
Добавлено позже:
Уже разобрался, тип же тоже меняется так что надо было писать
--- Код: ---template <typename T>
const Array<T> &Array<T>::operator=( const Array &right )
--- Конец кода ---
Добавлено позже:
И всё равно не смог я всё подружить с шаблоном, перегрузка операций ввода и вывода у меня говорят что объявляю я их криво , посмотрите пожалуйста.
P.S main находится в Array.cpp.
HoRRoR:
Нельзя шаблонные функции описывать в cpp. Там будут присутствовать только те шаблонные типы, которые использовались. Т.е. если ты используешь Array<int> в .cpp, то он будет там присутствовать, иначе - нет. Так что всё описывай в .h.
gepar:
Ну я пробовал перенести перегрузку ввода и вывода в .h файл, но это не помогло, сейчас попробую всё перенести туда.
Ну и маленькая программка для разминки из примера преподши (я добавил только вывод в каждой функции чтобы было видно что запускается)
--- Код: ---#include<iostream>
using std::cout;
//Перегрузка abs() тремя способами
int abs(int n);
long abs(long n);
double abs(double n);
int main()
{
cout<<"Absolute -10: "<<abs(-10)<<'\n';
cout<<"Absolute -10L: "<<abs(-10L)<<"\n";
cout<<"Absolute-10.01: "<<abs(-10.01)<< "\n";
return 0;
}
//abs() для целых
int abs(int n)
{
cout<<"NORMAL!!!!!";return n<0?-n:n; }
// abs() для длинных целых
long abs(long n)
{
cout<<"LONG!!!!!";return n<0?-n:n; }
// abs() для вещественных двойной точности
double abs(double n)
{cout<<"DOUBLE!!!!!";return n<0?-n:n; }
--- Конец кода ---
Собственно как это вообще работает? o_0 Судя по выводу (и по тому что для функцию int abs(int n) можно удалить) для int эта функция abs не используется вообще. Дальше каким это образом компилятор принимает -10L как аргумент функции, там же после цифры буква. Ну и почему идёт странный вывод в итоге: печатается сначала то что на вывод в потоке в функции я отправил, а потом уже что отправлено в поток в main o_0
Ведь по идеи должно печатать сначала Absolute -10L: из main'а, потом то что в функции на вывод отправлено LONG!!!!!, а потом уже число после обработки которое возвращает функция так почему же всё происходит совсем не так?
HoRRoR:
Ты основы вообще изучал? В частности - порядок вычисления выражения. Сначала вычисляется функция (в ней срабатывает вывод), а уже затем только вывод в main с результатом вычисления функции.
А буквы в конце констант вообще стыдно не знать. L - long, U - unsigned, F - float. 10ULL - unsigned long long, к примеру.
А с интом не работает, видимо, потому, что где-то эта функция уже определена. Если ты опишешь тело функции до main - то будет вызываться именно та, которая нужна.
gepar:
--- Цитата: HoRRoR ---Ты основы вообще изучал? В частности - порядок вычисления выражения. Сначала вычисляется функция (в ней срабатывает вывод), а уже затем только вывод в main с результатом вычисления функции.А буквы в конце констант вообще стыдно не знать. L - long, U - unsigned, F - float. 10ULL - unsigned long long, к примеру.
--- Конец цитаты ---
Ну я первый раз увидел чтобы вот так можно было дописать после цифры буквы в конце и компилятор это понял.
Добавлено позже:
А вот запихнуть всё в .h файл по отношению к шаблонам тоже не получилось, ну точнее в итоге я всё равно дохожу до ошибки как не извращаюсь...
Array.cpp||undefined reference to `operator<<(std::ostream&, Array<int> const&)'|
Посмотри пожалуйста.
HoRRoR:
Проблема в том, что у тебя этот оператор внутри класса описан не как шаблонная функция.
1. Опиши функции операторов выше, чем класс.
2. Для этого оставь выше этих функций упоминание о классе - template <typename T> class Array;
3. Измени описание friend'ов с учётом шаблона:
--- Код: --- friend ostream &operator<< <T>( ostream &, const Array<T> & );
friend istream &operator>> <T>( istream &, Array<T> & );
--- Конец кода ---
gepar:
--- Цитата: HoRRoR ---Проблема в том, что у тебя этот оператор внутри класса описан не как шаблонная функция.
--- Конец цитаты ---
Ну это я с самого начала заметил в виде предупреждений компилятора, но не знал как исправить это.
Так работает, спасибо за помощь. Но тут ещё хотелось бы хоть косвенно понять почему так .
Вот зачем было дописывать вот так например
--- Код: --- friend ostream &operator<< <T>( ostream &, const Array<T> & );
--- Конец кода ---
в итоге получается при вызове
--- Код: --- friend ostream &operator<< int ( ostream &, const Array<int> & );
--- Конец кода ---
что непонятно как работает (зачем int перед аргументами?)
Ну и почему надо было дружественные функции писать перед тем как их использовать (я же попробовал специально оставить их в конце - фигушки, так не получается).Ну хотя бы в двух словах.
HoRRoR:
Это каким чудом у тебя <int> превращается в int? Ты же не писал "operator << T (...". int в классе подставится вместо T таким образом:
--- Код: --- friend ostream &operator<< <int>( ostream &, const Array<int> & );
--- Конец кода ---
В самой функции это будет так:
--- Код: ---ostream &operator<<( ostream &output, const Array<int> &a )
--- Конец кода ---
Т.е. <int> по сути означает "typename T = int". Это как аргумент функции, только аргумент шаблона.
Проводя аналогию:
--- Код: ---void foo(int a);
...
foo(10);
template <typename T>
void foo(T a);
...
foo<int>(10);
--- Конец кода ---
Вот <int> - это передача аргумента шаблона.
gepar:
Я тут создаю свой класс вектор и в итоге получаю вот такое:
--- Код: ---C:\c++\Projects\Vector\Vector.cpp|137|error: cannot declare member function `static int Vector::getCount()' to have static linkage|
--- Конец кода ---
Собственно в первый раз с такой ошибкой встречаюсь,в чём может быть проблема?
В классе Vector в private есть
--- Код: ---static int count;// колличество созданных классов
--- Конец кода ---
Ну а функция по возврату этого значения выглядит как
--- Код: ---static int Vector::getCount()
{
return count;
}
--- Конец кода ---
Так в чём же тогда может быть проблема?
Добавлено позже:
Тьфу, static же в cpp файле не надо было писать уже, я и забыл.
Добавлено позже:
Почему при делении на число получается 1.#INF в выводе, когда я допустил ошибку (вместо равно в проверке условия написал присваивание)? Программа ведь должна была вылететь с кодом ошибки 100
Собственно .h файл
--- Код: ---# ifndef VECTOR_H
# define VECTOR_H
#include <iostream>
using std::ostream;
using std::istream;
class Vector
{
friend ostream &operator<<(ostream&,const Vector&);
public:
Vector();
Vector(const Vector&);
...
void operator/ (double);
static int getCount();
private:
int size; //количество элементов
int now;// состояние
double *vect;//сам вектор
static int count;// количество созданных классов
};
#endif
--- Конец кода ---
И функция деления:
--- Код: ---void Vector::operator/ (double p)
{
if (p=0)
exit(100);
if (size==1)
*vect/=p;
else
for (int i=0;i<size;i++)
vect[i]=(double)vect[i]/p;
}
--- Конец кода ---
Почему работа продолжается при такой ошибке, я ведь явно указал выход с ошибкой 100 и никаких или.
HoRRoR:
--- Цитата --- if (p=0)
exit(100);
--- Конец цитаты ---
Сам вдумайся в то, что ты написал.
Во-первых, это присваивание.
Во-вторых, оно всегда будет давать false.
В-третьих, даже при ненулевых значениях возможно получить INF - если число будет слишком маленьким, чтобы результат деления поместился.
В-четвёртых, возьми за правило писать double как 0.0, float как 0.0f.
gepar:
--- Цитата: HoRRoR ---Во-первых, это присваивание.
--- Конец цитаты ---
А я то и не заметил :). Я нашёл эту ошибку о чём и написал, но мне стало потом интересно почему же программа не вылетала каждый раз с кодом ошибки 100.
HoRRoR,тоесть оно присвоит p значение 0, но тем не менее будет идти как false? Но в таком случае оно дальше бы должно делить на 0 и вылететь всё равно с ошибкой.
HoRRoR:
Деление числа с плавающей запятой на ноль - не ошибка и даёт infinitiy.
Добавлено позже:
--- Цитата ---тоесть оно присвоит p значение 0, но тем не менее будет идти как false?
--- Конец цитаты ---
Выражение присваивания возвращает результат присваивания. Т.е. (a = 1) == 1 - true. И тут так же, только с нулём, а ноль - это false.
gepar:
HoRRoR,ага, вот так оно расценило моё условие, теперь понятно.
--- Цитата: HoRRoR ---Деление числа с плавающей запятой на ноль - не ошибка и даёт infinitiy.
--- Конец цитаты ---
Я думал деление на 0 хоть int, хоть double будет приводить к ошибке при выполнении, а оно во как. Спасибо, буду знать.
gepar:
Читаю о манипуляторах потоков и тут тоже возникли некоторые вопросы.
Есть ли разница между
--- Код: ---# include <iostream>
using namespace std;
int main()
{
char *abc="word";
cout<<abc<<'\n';
cout<<static_cast<void*> (abc); // и cout<<(void*) abc;
}
--- Конец кода ---
HoRRoR:
Разница только в операторах приведения типа, поток тут можно и не затрагивать.
gepar:
А как бы его избавиться от пробелов в этом случае
--- Код: --- char abc[80];
cin.getline(abc,80,EOF);
--- Конец кода ---
? Вычитал что есть некаю skipws, но что-то никак не придумаю как бы её подпихнуть во входной поток.
HoRRoR:
http://www.cplusplus.com/reference/iostream/manipulators/skipws/
Вообще и самому пробелы убрать можно, раз уж строку целиком читаешь. Или читать посимвольно, игнорируя пробелы.
Навигация
Перейти к полной версии