自打引用传递及设计模式 (上)

1  值传递

  值传递是 拷贝实参的值
传于形参,常用于“小目标” (small objects)

int fact(int val)   // factorial of val 
{
    int ret = 1; 

    while (val > 1)  // assign ret * val to ret and decrement val
        ret *= val--; 

    return ret;
}

  调用下面函数,便是价值传递:

cout << "5! is " << fact(5) << endl;

  小目标一般也:坐类型(built-in
types),STL迭代器,函数对象类型(function object types)

  只包含一针对性数码(x,y) 的 Point 类,也实属小目标

void Point::operator+=(Point delta); // pass-by-value

 

2  引用传递

  引用传递不关乎拷贝,传递让形参的凡实参变量的援,其发出零星单亮点:更迅速与防切断,常用来传递“大数值”
(large values) 

2.1  更高效

  基类 Person,派生类 Student

class Person{
private:
    std::string name;
    std::string address;
};

class Student: public Person{
private:
    std::string schoolName;
    std::string schoolAddress;
};

  现有一个证明学生身份的函数,形参为价值传递,则拷贝实参给形参的代价是:

  调用 Person 构造函数一不行,基类内 string
型数据成员的构造函数两糟糕;Student 构造函数一蹩脚,派生类内 string
型数据成员两涂鸦;最后还会见调用相应的析构函数六次于,共计十二次于调用,自然效率低下。

  而引用传递,并无干拷贝操作,故显著的增长了效率。

bool validateStudent(Student s);    // pass-by-value 

bool validateStudent(const Student& s);  // pass-by-reference-to-const 

2.2  防切断

  下面的例证中,派生类 WindowWithScrollBars 中,重写了基类 Window
的虚函数 display

class Window {
public: 
    std::string name() const;        // return name of window
    virtual void display() const;    // draw window and contents
};

class WindowWithScrollBars : public Window {
public:
    virtual void display() const;
};

  在 printNameAndDisplay 函数中,调用了
dispaly 函数,而亮参若采用值传递方式,则会生“切断” (slicing),即 wwsb
调用的凡 Window::display()

  因为以 printNameAndDisplay
中,并无修改传递进入的参数,假如下 pass-by-const-reference
的款式,则会避免“切断”的发生

void printNameAndDisplay(Window w)
{
    std::cout << w.name();
    w.display();
}

// WindowWithScrollBars object will be sliced off
WindowWithScrollBars  wwsb;
printNameAndDisplay(wwsb);

 

3  动态绑定

  上面”切断”的事例,实际上干的是 C++ 的动态绑定机制 (dynamic
binding), 而动态绑定的一个至关重要就是是援传递,看下例子:

class Quote {
public:
    std::string isbn() const;
    virtual double net_price(std::size_t n) const;
};

class Bulk_quote : public Quote { 
public:
    double net_price(std::size_t) const override;
};

  在 cal_total 函数中,需要调用 net_price,采用
pass-by-const-reference 形式

double cal_total(const Quote &item, size_t n)  // calculate the price
{
    double ret = item.net_price(n);
    return ret;
}

  调用 Quote::net_price 还是 Bulk_quote::net_price,
取决于传递进入的参数

// basic is type Quote; bulk is type Bulk_quote
cal_total(basic, 20); //  Quote::net_price
cal_total(bulk, 20);  //  Bulk_quote::net_price

   C++
的动态绑定也给“迟邦定”,它若程序直到运行时,才基于引用或指针绑定的对象类型,来摘取调用哪个虚函数

 

4  设计模式 

    前面说及,动态绑定的一个至关重要是引用传递。它还有其他一个重要 —
虚函数,例 2.2 中的 display 为虚函数,例 3 中之 net_price
同样为是虚函数。

 4.1  模板方法

   有同一栽编程惯例叫做 NVI (non-virtural interface) — 非虚拟接口
将所有的国有函数 (public) 声明也非虚拟的,也就虚函数声明也个体或保护
(private or protected)

   该 NVI 惯例的落实,是通过同样栽设计模式 —— 模板方法 (template method)
来就的

  C++ 1

 1)  AbstractClass: TemplateMethod 为非虚成员函数 (public),函数体内调用
PrimitiveOperation1 同 PrimitiveOperation2 两独虚函数(protected)

 2)  ConcreteClass: 继承自 AbstractClass, 重写了片只虚函数
PrimitiveOperation1 及 PrimitiveOperation2

4.2  代码实现

  按该模式则例 3 中 Quote 里,可拿 cal_total
声明也国有非虚成员函数,net_price 则声称也保护型,Bulk_quote
公有继承自 Quote,且还写虚函数 net_price

  但在骨子里被,只有当 cal_total 内至少含有两个像样 net_price 的操作函数
(比如先调用 net_price 再 print_price),才起利用设计模式的画龙点睛

  下面是模板方法模式之简约示例:

class AbstractClass {
public:
    void TemplateMethod();
protected:
    virtual void PrimitiveOperation1() = 0;
    virtual void PrimitiveOperation2() = 0;
};

class ConcreteClass : public AbstractClass {
protected:
    void PrimitiveOperation1() override;
    void PrimitiveOperation2() override;
};

void AbstractClass::TemplateMethod()
{
    PrimitiveOperation1();
    PrimitiveOperation2();
}

  
由地方的例子可以望,模板方法是有关基类如何调用派生类内操作函数的,是平栽反向控制结构,常用于代码复用。

  这种反向结构为体现了一个企划原则,即好莱坞原则
“不要为咱们打电话,我们会打给您”

 

小结:

1) use pass-by-value for small objects;use
pass-by-const-reference to pass large values that you don’t
need to modify

2) dynamic binding happens when a virtual function is called
through a reference (or a pointer) to a base class

3) Tempalte method pattern – define the skeleton of an algorithm in
an operation, deferring some steps to subclasses.

 

参考资料:

 <C++ Programming Language_4th> ch 12.2.1

 <Effective C++_3rd> item 20

 <C++ Primer_5th> ch 6.2,  ch 15.1

 <Design Patterns> template method