zoukankan      html  css  js  c++  java
  • 什么时候用引用,什么时候用指针的一个小例子

      之前也知道引用和指针的区别,但如果现在让我说他们两个有什么区别,我还是不太能全部说出来,(红色标记一下:引用和指针的异同有哪些?)之所以不能说出他两的区别,不是因为我记忆力不好,而是没有过实际代码的体验。在看Essential C++时,碰到下面的代码,感觉能够说明一些他两的用法。下面给出代码和书上的说明:

    首先说明一下这里基类num_sequence和子类Fibonacci的目的。基类是一系列不同类型数列的抽象,比如斐波那契数列等等(这里仅以Fibonacci来举例说明子类)。先给出第一次设计基类和子类的代码:(第一次设计时基类不保存具体的数列Vector,只是一些子类抽象出来的函数)

    1 基类

      1.1 num_sequence.h

    num_sequence.h 
     1 #pragma once
    2 #include <iostream>
    3
    4 class num_sequence
    5 {
    6 public:
    7 num_sequence(void);
    8 virtual ~num_sequence(void);
    9 virtual int elem( int pos ) const = 0; //返回子类pos位置的元素
    10 virtual const char* what_am_i() const = 0; //返回子类的名字,比如Fibonacci
    11 virtual std::ostream& print( std::ostream& os = std::cout ) const = 0; //console输出子类的成员变量信息
    12 friend std::ostream& operator<<( std::ostream &os, const num_sequence &ns );
    13 static int max_elems() { return _max_elems; } //返回子类最多可以包含的元素个数
    14
    15
    16 protected:
    17 virtual void gen_elems( int pos ) const = 0; //给子类中添加元素
    18
    19 bool check_integrity( int pos ) const; //验证子类pos位置是否合法
    20
    21 const static int _max_elems = 1024; //子类数列最多可以包含的元素个数
    22 };

      1.2 num_sequence.cpp

    num_sequence.cpp
     1 #include "StdAfx.h"
    2 #include "num_sequence.h"
    3
    4 num_sequence::num_sequence(void)
    5 {
    6 }
    7
    8 num_sequence::~num_sequence(void)
    9 {
    10 }
    11
    12
    13 bool num_sequence::check_integrity( int pos ) const
    14 {
    15 if ( pos <= 0 || pos > _max_elems )
    16 {
    17 std::cerr << "!! invalid position: " << pos << " Cannot honor request\n" ;
    18 return false;
    19 }
    20 return true;
    21 }
    22
    23 std::ostream& operator<<( std::ostream &os, const num_sequence &ns )
    24 {
    25 return ns.print( os );
    26 }

    2 子类

      2.1 Fibonacci.h

    Fibonacci.h
     1 #pragma once
    2 #include "num_sequence.h"
    3 #include <vector>
    4 class Fibonacci :
    5 public num_sequence
    6 {
    7 public:
    8 Fibonacci( int len = 1, int beg_pos = 1 );
    9 ~Fibonacci(void);
    10
    11 virtual int elem( int pos ) const;
    12 virtual const char* what_am_i() const { return "Fibonacci"; }
    13 virtual std::ostream& print( std::ostream& os = std::cout ) const;
    14
    15
    16 int length() const { return _length; }
    17 int beg_pos() const { return _beg_pos; }
    18
    19 protected:
    20 virtual void gen_elems( int pos ) const;
    21 bool check_integrity( int pos, int size ) const; //必须声明
    22 int _length;
    23 int _beg_pos;
    24
    25 static std::vector<int> _elems; //保存数列的元素
    26 };

      2.2 Fibonacci.cpp

    Fibonacci.cpp
     1 #include "StdAfx.h"
    2 #include "Fibonacci.h"
    3
    4
    5 std::vector<int> Fibonacci::_elems;
    6
    7
    8 Fibonacci::Fibonacci( int len, int beg_pos ) : _length(len), _beg_pos(beg_pos) {}
    9
    10 Fibonacci::~Fibonacci(void)
    11 {
    12 }
    13
    14 int Fibonacci::elem( int pos ) const
    15 {
    16 if ( ! check_integrity(pos, _elems.size() ) )
    17 {
    18 return 0;
    19 }
    20 if ( pos > _elems.size() )
    21 {
    22 Fibonacci::gen_elems( pos );//一会测试一下改成执行期才决定选择哪个gen_elems
    23 }
    24
    25 return _elems[ pos-1 ];
    26 }
    27
    28
    29 void Fibonacci::gen_elems( int pos ) const
    30 {
    31 if ( _elems.empty() )
    32 {
    33 _elems.push_back( 1 );
    34 std::cout << "gen_elems: " << 1 << std::endl;
    35 _elems.push_back( 1 );
    36 std::cout << "gen_elems: " << 1 << std::endl;
    37 }
    38
    39 if ( _elems.size() <= pos )
    40 {
    41 int ix = _elems.size();
    42 int n_2 = _elems[ ix-2 ];
    43 int n_1 = _elems[ ix-1 ];
    44
    45 for ( ; ix <= pos; ++ix )
    46 {
    47 int elem = n_2 + n_1;
    48 _elems.push_back( elem );
    49 std::cout << "gen_elems: " << elem << std::endl;
    50 n_2 = n_1;
    51 n_1 = elem;
    52 }
    53 }
    54 }
    55
    56 std::ostream& Fibonacci::print( std::ostream& os ) const
    57 {
    58 int elem_pos = _beg_pos - 1;
    59 int end_pos = elem_pos + _length;
    60
    61 if ( end_pos > _elems.size() )
    62 {
    63 Fibonacci::gen_elems( end_pos );//这里和int Fibonacci::elem( int pos ) const中一样是
    64 } //因为已经可以确定是执行Fibonacci的gen_elems函数,所以明确的告诉编译器,以便跳过虚拟函数机制
    65
    66 while ( elem_pos < end_pos )
    67 {
    68 os << _elems[ elem_pos] << ' ';
    69 ++elem_pos;
    70 }
    71
    72 return os;
    73 }
    74
    75 bool Fibonacci::check_integrity( int pos, int size ) const
    76 {
    77 if ( pos <= 0 || pos > _max_elems )
    78 {
    79 std::cerr << "!! invalid position: " << pos << " Cannot honor request\n" ;
    80 return false;
    81 }
    82
    83 if ( pos > size )
    84 {
    85 gen_elems( pos ); //通过虚拟机制调用
    86 }
    87 return true;
    88 }

    前面这些代码给出了第一次设计时候的思想,现在第二次设计时把一些子类都要用到的数据抽象到基类里,比如子类实际存储的vector等等。

     1 class num_sequence
    2 {
    3
    4 public:
    5 virtual ~num_sequence() {}
    6 virtual const char* what_am_i() const = 0;
    7 int elem( int pos ) const;
    8 ostream& print( ostream& os = cout ) const;
    9 int length() const { return _length;}
    10 int beg_pos() const { return _beg_pos; }
    11 static int max_elems() { return 64; }
    12
    13 protected:
    14 virtual void gen_elems( int pos ) const = 0;
    15 bool check_integrity( int pos, int size ) const;
    16
    17 num_sequence( int len, int bp, vector<int> &re )
    18 : _length( len ), _beg_pos( bp ), _relems( re ) {}
    19 int _length;
    20 int _beg_pos;
    21 vector<int> &_relems;
    22 };

    这里红色标记的地方是比较重要的地方:

      1、_relems声明为引用原因:reference永远无法代表空对象( null object ),pointer却可能是null。让它成为reference,我们就再也不必检查它是否为null了

      data members如果是reference,则必须在constructor的member initialization list中加以初始化一旦初始化后,就再也无法指向另一个对象如果data members是个pointer,就无此限制:我们可以再constructor内加以初始化,也可以先将它初始化为null,稍后再令它指向某个有效的内存地址

      2、num_sequence 的constructor为protected原因:num_sequence乃是一个抽象基类,我们无法为它定义任何对象。num_sequence扮演的角色是每个派生类对象的子对象(subobject)。基于这个理由,我们将基类的constructor声明为protected而非public

    到这里本次文章的主要目的就结束了。但还有一个问题先记下来,方便以后回头查看:

      copy assignment operator 和 copy constructor的问题:Essential C++ P105 Triangular t3 = 8;会调用带有单一参数的constructor

      今天查了一下,大体上了解了为什么“Essential C++ P105 Triangular t3 = 8;会调用带有单一参数的constructor”。这里是因为之前尚未定义t3,如果之前已经定义过了,那么就是copy assignment operator (参考文献:http://blog.sina.com.cn/s/blog_48d4d2df010002n9.html

      



     

  • 相关阅读:
    HDU 5120 计算两圆环相交面积
    HDU
    Dinic (邻接表实现) + 当前弧优化
    java —— static 关键字
    java —— this 关键字
    双连通分量 Road Construction POJ
    2-SAT(HDU-3062 party)
    java——构造器理解
    『题解』Codeforces1142A The Beatles
    『题解』Codeforces1142B Lynyrd Skynyrd
  • 原文地址:https://www.cnblogs.com/ziyoudefeng/p/2407197.html
Copyright © 2011-2022 走看看