Эффективное использование C ++ пункт 37: Наследование и объектно-ориентированная сумма (не переопределять значение параметров по умолчанию, унаследованное)

предисловие

  • 36 в терминах , введенных в иерархии наследования, производный класс предпочтительно покрывает только переопределять виртуальные функции , не будет скрывать не-виртуальный базовый класс
  • Таким образом, это положение , чтобы ввести «Не переопределять значения параметров по умолчанию наследуется,» для виртуальной функции в терминах
  • Важное понятие: виртуальные функции динамически связаны, но значения параметров по умолчанию виртуальной функция статический связана

Во-первых, статический тип и динамический тип

  • Статические типов: тип в декларациипринятый
  • Динамические типы: текущее знание типа объекта

Клинический случай

  • Вот иерархия наследования
class Shape {
public:
    enum ShapeColor { Red, Green, Blue };
    virtual void draw(ShapeColor color = Red)const = 0;
};

class Rectangle :public Shape {
public:
    virtual void draw(ShapeColor color = Green)const = 0;
};

class Circle :public Shape {
public:
    virtual void draw(ShapeColor color)const = 0;
};

  • Теперь мы определим следующий код, они объявлены как Пинтер к Shpae типов, поэтому они независимо от того, на что они указывают, статический тип Shape *:
Shape* ps;                 //静态类型为Shape*
Shape* pc = new Circle;    //静态类型为Shape*
Shape* pr = new Rectangle; //静态类型为Shape*
  • Динамический тип объекта означает, что там будет любое поведение. Например:
Shape* ps;
Shape* pc = new Circle;
Shape* pr = new Rectangle;

ps = pc; //ps的动态类型如今是Circle*
ps = pr; //ps的动态类型如今是Rectangle*
  • Мы знаем, что в соответствии с синтаксисом для вызова виртуальных функций, определяются в соответствии с его динамическим типа. Например:
Shape* ps;                 
Shape* pc = new Circle; 
Shape* pr = new Rectangle;

pc->draw(Shape::Red); //调用Circle::draw(Shape::Red)
pr->draw(Shape::Red); //调用Rectangle::draw(Shape::Red)

Во-вторых, параметр по умолчанию значения виртуальных функций статически связаны

  • Хотя время для вызова виртуальных функций динамически связанные, но значения параметров по умолчанию для виртуальной функции статически связан
  • Смотрите следующий код:
    • Мы знаем , что виртуальные функции динамически связаны, динамический тип пр Rectangle, поэтому вызов Прямоугольник :: Draw ()
    • Однако значения параметров по умолчанию виртуального статический оценка функции, функция прямоугольник в определении выше класс дро () без параметров, но изза статическим тип пр указателя Shape, поэтому выты значения параметровумолчанию (функции) это функция Shape :: Жеребьевка () значений параметров для Shape :: Red
Shape* pr = new Rectangle;
pr->draw(); //调用的是Rectangle::draw(Shape::Red)


//Circle也是相同的道理
Shape* pc = new Circle;
pc->draw(); //调用的是Circle::draw(Shape::Red),而不是Circle::draw(Shape::Green)
  • Почему дизайн такого поведения: что операционная эффективность. Если значения по умолчанию являются параметр динамического связывания, компилятор должен быть какойто способчтобы определить соответствующие значения параметровумолчанию для виртуальных функций во время выполнения, что медленнее и сложнеечем механизм «при компиляции решения времени»настоящее время на месте

В-третьих, не переопределить значения параметров по умолчанию, унаследованных

  • По - вторых, мы знаем , что параметр по умолчанию значения виртуальных функций статически связаны. Таким образом, мы не переопределить значение параметров по умолчанию наследуется, потому что он будет производить неожиданные результаты при вызове виртуальной функции (выше код вызывает ничью с помощью ПК () является примером)

В-четвертых, ответ на рекомендации, содержащиеся в виртуальной функции значений параметров по умолчанию, учитывая

Неэффективный вид программы

  • Для согласованности в базовом классе и производный класс, и является неэффективным методом установки базы значения параметра по умолчанию и производный класс виртуальной функция соответствует
  • Например:
class Shape {
public:
    enum ShapeColor { Red, Green, Blue };
    virtual void draw(ShapeColor color = Red)const = 0;
};

class Rectangle :public Shape {
public:
    virtual void draw(ShapeColor color = Red)const;
};

class Circle :public Shape {
public:
    virtual void draw(ShapeColor color = Red)const;
};
  • Неэффективные причины:
    • ① дублирования кода
    • ② зависимость слишком высока, если значения параметров по умолчанию в базовом классе изменилась, вам необходимо значения параметров по умолчанию, производный класс в модифицируют снова

NVI способ определить класс

  • Пункт 36 вводит методы, Nvi для значений параметров по умолчанию virutal функции, для того, чтобы избежать дефолта базового параметра класса и полученные значения класса не совпадают, мы можем принять этот подход
  • Код определяется следующим образом:
class Shape {
public:
    enum ShapeColor { Red, Green, Blue };
    void draw(ShapeColor color = Red)const { //因为是non-virtual函数,因此不建议派生类隐藏
        doDraw(Red);
    }
private:
    //真正的工作在此处完成,派生类可以重写
    virtual void doDraw(ShapeColor color)const = 0;
};


class Rectangle :public Shape {
private:
    virtual void doDraw(ShapeColor color)const = 0;
};
  • Выше функция doDraw (), чтобы завершить действительную функцию, и принимает тип ShapeColor
  • Мы определили , не виртуальную функцию дры, его параметры по умолчанию в Red, и не виртуальная функция не рекомендует производный класс , чтобы скрыть, так ли это базовый класс или производный класс вызывает дро () по умолчанию действует, параметр всегда будет красным чтобы достичь нашей конечной цели

V. Резюме

  • Никогда переопределить значение параметра, по умолчанию наследуется, поскольку значения по умолчанию являются параметр статических привязки, и virutal функции - единственной вещью, которую вы должны быть покрыты - это динамическое связывание
发布了1525 篇原创文章 · 获赞 1085 · 访问量 45万+

рекомендация

отblog.csdn.net/qq_41453285/article/details/104818312