Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #include <iostream>
- /* не написали на семинаре, forward объявление класса
- * чтобы компилировалась функция ниже */
- template<typename T>
- class Fractional;
- /* функция, которую сделаем другом */
- template<typename T>
- void someFunction(const Fractional<T>& f) {
- std::cout << f.top_ << "\n"; // есть доступ к private, т.к. друг
- }
- template<typename T = int>
- class Fractional {
- public:
- Fractional(): Fractional(0, 1) {}
- Fractional(T top, T bottom): top_(top), bottom_(bottom) {}
- /* если хотим запретить неявное приведение, убираем коммент
- * желательно всегда использовать explicit, но для арифметических
- * классов удобно иметь неявное приведение */
- /*explicit*/ Fractional(T top): Fractional(top, 1) {}
- /*то же самое, но короче с аргументами по умолчанию:
- * Fractional(T top = 0, T bottom = 1): top_(top), bottom_(bottom) {}
- * использование делегирования более наглядно */
- T getTop() const;
- /* определено внутри класса, inline по умолчанию
- * для большинства методов правильнее выносить реализацию за пределы класса */
- T getBottom() const {
- return bottom_;
- }
- void setTop(T top) {
- top_ = top;
- }
- /* этот вариант корректный, но не поддерживает смешанную арифметику
- * например 5 * f */
- /*const Fractional operator*(const Fractional& rs) const {
- return Fractional(top_ * rs.top_, bottom_ * rs.bottom_);
- }*/
- Fractional& operator*=(const Fractional& rs) {
- top_ *= rs.top_;
- bottom_ *= rs.bottom_;
- return *this;
- }
- /* friend функции по сути внешние даже если определены внутри класса
- * поэтому вызываются не для объекта, не могут быть константными
- * имеют доступ к private класса - друзей должно быть как можно меньше
- * класс шаблонный - определяя внутри и делая другом, поддерживаем смешанную арифметику */
- friend const Fractional operator*(Fractional ls, const Fractional& rs) {
- //return Fractional(ls.top_ * rs.top_, ls.bottom_ * rs.bottom_);
- /* не дублируем код, во многих случаях легче реализовывать * через *=,
- * а не наоборот (аналогично для остальных) */
- return ls *= rs;
- }
- /* явное приведение типа для if (f) и подобного */
- explicit operator bool() const {
- return top_ != 0;
- }
- /* оператор вывода в поток. Возвращаем ссылку на используемый поток, чтобы
- * можно было продолжить вывод далее. Используем ссылки, т.к. out при выводе
- * изменяется */
- friend std::ostream& operator <<(std::ostream& out, const Fractional& f) {
- out << f.getTop() << "/" << f.getBottom();
- return out;
- }
- /* примеры объявления друзей */
- friend void someFunction<T>(const Fractional&); // обратите внимание на <T>
- /* friend class SomeClass; */
- private:
- T top_, bottom_;
- };
- template<typename T>
- T Fractional<T>::getTop() const {
- return top_;
- }
- /* примерный С-эквивалент методов (допустим Fractional нешаблонный) */
- /* int Fractional_getTop(const Fractional *const this) {
- return this->top_;
- }
- void Fractional_setTop(Fractional * const this, int top) {
- this->top_ = top;
- }*/
- /* void func(const Fractional& f) {
- std::cout << f.getTop() << "\n";
- }*/
- template<typename T>
- T max(const T& ls, const T& rs) {
- return ls > rs ? ls : rs;
- }
- int main() {
- Fractional<> f(1, 2);
- /* эквивалентно
- * operator<<(operator<<(std::cout, f), "\n") */
- std::cout << f << "\n";
- Fractional<int> integer_first(3);
- someFunction(integer_first);
- Fractional<int> integer_second = 3; //неявное приведение типа
- /* не использовать (кроме арифметики), без explicit можно напороться на такое:
- * std::string some_string = 'a'; */
- /* когда Fractional был нешаблонным, без explicit был возможен вызов
- func(5); */
- Fractional<int> integer_third = Fractional<int>(3); // 3-я форма вызова, аналогично 1-ой
- const Fractional<int> some_const(6);
- std::cout << some_const.getTop() << "\n"; // const важен
- /* a * b раскрывается в a.operator*(b), если такого нет, то
- * в operator*(a, b) (внешний) */
- Fractional<int> mul = f * integer_first; // по сути вызов operator*(f, integer_first)
- integer_first *= (integer_second *= some_const); // можно и так
- /* отличия шаблонных функций от классов
- * функция выводит тип шаблона по аргументам вызова, например
- * max(5, 3) -> T = int
- * если вывод невозможен, то можем указать явно */
- size_t y = 5u;
- int x = max<int>(y, 3);
- /* для классов вывод невозможен, всегда указываем параметр
- * при этом компилируются только используемые методы
- * в примере ниже компилируется только конструктор и setTop */
- Fractional<> test(7);
- test.setTop(8);
- /* Fractional<int> и Fractional<double> абсолютно разные типы
- * компилятор по сути дублирует код */
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement