Advertisement
Guest User

seminar

a guest
Oct 3rd, 2016
111
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 6.25 KB | None | 0 0
  1. #include <iostream>
  2.  
  3. /* не написали на семинаре, forward объявление класса
  4.  * чтобы компилировалась функция ниже */
  5. template<typename T>
  6. class Fractional;
  7.  
  8. /* функция, которую сделаем другом */
  9. template<typename T>
  10. void someFunction(const Fractional<T>& f) {
  11.     std::cout << f.top_ << "\n"; // есть доступ к private, т.к. друг
  12. }
  13.  
  14. template<typename T = int>
  15. class Fractional {
  16. public:
  17.     Fractional(): Fractional(0, 1) {}
  18.  
  19.     Fractional(T top, T bottom): top_(top), bottom_(bottom) {}
  20.  
  21.     /* если хотим запретить неявное приведение, убираем коммент
  22.      * желательно всегда использовать explicit, но для арифметических
  23.      * классов удобно иметь неявное приведение */
  24.     /*explicit*/ Fractional(T top): Fractional(top, 1) {}
  25.  
  26.     /*то же самое, но короче с аргументами по умолчанию:
  27.      * Fractional(T top = 0, T bottom = 1): top_(top), bottom_(bottom) {}
  28.      * использование делегирования более наглядно */
  29.  
  30.     T getTop() const;
  31.  
  32.     /* определено внутри класса, inline по умолчанию
  33.      * для большинства методов правильнее выносить реализацию за пределы класса */
  34.     T getBottom() const {
  35.         return bottom_;
  36.     }
  37.  
  38.     void setTop(T top) {
  39.         top_ = top;
  40.     }
  41.  
  42.     /* этот вариант корректный, но не поддерживает смешанную арифметику
  43.      * например 5 * f */
  44.     /*const Fractional operator*(const Fractional& rs) const {
  45.         return Fractional(top_ * rs.top_, bottom_ * rs.bottom_);
  46.     }*/
  47.  
  48.     Fractional& operator*=(const Fractional& rs) {
  49.         top_ *= rs.top_;
  50.         bottom_ *= rs.bottom_;
  51.         return *this;
  52.     }
  53.  
  54.     /* friend функции по сути внешние даже если определены внутри класса
  55.      * поэтому вызываются не для объекта, не могут быть константными
  56.      * имеют доступ к private класса - друзей должно быть как можно меньше
  57.      * класс шаблонный - определяя внутри и делая другом, поддерживаем смешанную арифметику */
  58.     friend const Fractional operator*(Fractional ls, const Fractional& rs) {
  59.         //return Fractional(ls.top_ * rs.top_, ls.bottom_ * rs.bottom_);
  60.         /* не дублируем код, во многих случаях легче реализовывать * через *=,
  61.          * а не наоборот (аналогично для остальных) */
  62.         return ls *= rs;
  63.     }
  64.  
  65.     /* явное приведение типа для if (f) и подобного */
  66.     explicit operator bool() const {
  67.         return top_ != 0;
  68.     }
  69.  
  70.     /* оператор вывода в поток. Возвращаем ссылку на используемый поток, чтобы
  71.      * можно было продолжить вывод далее. Используем ссылки, т.к. out при выводе
  72.      * изменяется */
  73.     friend std::ostream& operator <<(std::ostream& out, const Fractional& f) {
  74.         out << f.getTop() << "/" << f.getBottom();
  75.         return out;
  76.     }
  77.  
  78.     /* примеры объявления друзей */
  79.     friend void someFunction<T>(const Fractional&); // обратите внимание на <T>
  80.     /* friend class SomeClass; */
  81. private:
  82.     T top_, bottom_;
  83. };
  84.  
  85. template<typename T>
  86. T Fractional<T>::getTop() const {
  87.     return top_;
  88. }
  89.  
  90. /* примерный С-эквивалент методов (допустим Fractional нешаблонный) */
  91.  
  92. /* int Fractional_getTop(const Fractional *const this) {
  93.     return this->top_;
  94. }
  95.  
  96. void Fractional_setTop(Fractional * const this, int top) {
  97.     this->top_ = top;
  98. }*/
  99.  
  100. /* void func(const Fractional& f) {
  101.     std::cout << f.getTop() << "\n";
  102. }*/
  103.  
  104. template<typename T>
  105. T max(const T& ls, const T& rs) {
  106.     return ls > rs ? ls : rs;
  107. }
  108.  
  109. int main() {
  110.     Fractional<> f(1, 2);
  111.  
  112.     /* эквивалентно
  113.      * operator<<(operator<<(std::cout, f), "\n") */
  114.     std::cout << f << "\n";
  115.  
  116.     Fractional<int> integer_first(3);
  117.     someFunction(integer_first);
  118.     Fractional<int> integer_second = 3; //неявное приведение типа
  119.     /* не использовать (кроме арифметики), без explicit можно напороться на такое:
  120.      * std::string some_string = 'a'; */
  121.  
  122.     /* когда Fractional был нешаблонным, без explicit был возможен вызов
  123.     func(5); */
  124.     Fractional<int> integer_third = Fractional<int>(3); // 3-я форма вызова, аналогично 1-ой
  125.     const Fractional<int> some_const(6);
  126.     std::cout << some_const.getTop() << "\n"; // const важен
  127.  
  128.     /* a * b раскрывается в a.operator*(b), если такого нет, то
  129.      * в operator*(a, b) (внешний) */
  130.     Fractional<int> mul = f * integer_first; // по сути вызов operator*(f, integer_first)
  131.     integer_first *= (integer_second *= some_const); // можно и так
  132.  
  133.     /* отличия шаблонных функций от классов
  134.      * функция выводит тип шаблона по аргументам вызова, например
  135.      * max(5, 3) -> T = int
  136.      * если вывод невозможен, то можем указать явно */
  137.     size_t y = 5u;
  138.     int x = max<int>(y, 3);
  139.  
  140.     /* для классов вывод невозможен, всегда указываем параметр
  141.      * при этом компилируются только используемые методы
  142.      * в примере ниже компилируется только конструктор и setTop */
  143.     Fractional<> test(7);
  144.     test.setTop(8);
  145.  
  146.     /* Fractional<int> и Fractional<double> абсолютно разные типы
  147.      * компилятор по сути дублирует код */
  148.  
  149.     return 0;
  150. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement