C++的结构数组定义和运算符重载

问题遇到的现象和发生背景

结构缓冲区buffer 存放固定长度,固定类型的数组

问题相关代码,请勿粘贴截图

#include <iostream>
#include <stdexcept>
 
class BufferIndexError : public //* *//
 
{
private:
  int index;
public:
  BufferIndexError(int idx) : std::out_of_range(""), index(idx) {}
  int getIndex() const { return index; }
};
 
template <typename T, int N>
struct Buffer
{
  int size() const
  {
    //* *//
;
  }
  bool empty() const
  {
    //* *//
;
  }
  const T& operator[](int i) const
  {
    if (//* *//)
      return elems[i];
    
//* *// BufferIndexError(i);
  }
  const T& front() const
  {
    //* *// 
;
  }
  const T& back() const
  {
    //* *//
;
  }
 //* *//
  
 elems[//* *//];
};
 
 //* *//
 //* *//   operator<<(std::ostream &out, const Buffer<T, N> &buf)
{
  for (int i = 0; i < N; ++i)
    //* *//
;
  return out;
}
 
int main()
{
  Buffer<int, 4> numbers = {1, 3, 1, 4};
  Buffer<int, 0> no_numbers;
  std::cout << "numbers.empty(): " << numbers.empty() << '\n';
  std::cout << "no_numbers.empty(): " << no_numbers.empty() << '\n';
 
  Buffer<char, 16> letters = {
    'D','o',' ','n','o','t',' ','a','n','s','w','e','r','!','!','!'
  };
  if (!letters.empty())
  {
    std::cout << "The first character is: " << letters.front() << '\n';
    std::cout << "The last character is: " << letters.back() << '\n';
  }
  std::cout << letters << '\n';
 
  //* *//
 
  {
    int k = 0;
    while (true)
      std::cout << letters[k++];
  }
  
 //* *//
  {
    std::cout << "\nBuffer index is out of range: " << ex.//* *//() << std::endl;
  }
}
 

运行结果及报错内容

应该有这个struct的类方法定义和<<运算符的重载两部分组成
其中//* *//都是需要补足的地方

img

img

img

img

最终程序的运行结果

numbers.empty(): 0
no_numbers.empty(): 1
The first character is: D
The last character is: !
Do not answer!!!
Do not answer!!!
Buffer index is out of range: 16 

我的解答思路和尝试过的方法

但是我不知道具体的语句怎么填

我想要达到的结果

完成程序的填空 达到理性的运行结果

img

完整代码如下:


#include <iostream>
#include <stdexcept>

class BufferIndexError : public std::out_of_range //填空1
{
private:
    int index;
public:
    BufferIndexError(int idx) : std::out_of_range(""), index(idx) {}
    int getIndex() const { return index; }
};

template <typename T, int N>
struct Buffer
{
    int size() const
    {
        return N;//填空
    }
    bool empty() const
    {
        return N==0; //填空
    }
    const T& operator[](int i) const
    {
        if (i>=0 && i < N) //填空
            return elems[i];
        throw //填空
            BufferIndexError(i);
    }
    const T& front() const
    {
        return elems[0]; //填空
    }
    const T& back() const
    {
        return elems[N-1]; //填空
    }
    

    T elems[N];// 填空
};

template <typename T, int N> //填空
std::ostream& operator<<(std::ostream &out, const Buffer<T, N> &buf) //填空
{
    for (int i = 0; i < N; ++i)
        out << buf[i] ;
    return out;
}

int main()
{
    Buffer<int, 4> numbers = { 1, 3, 1, 4 };
    Buffer<int, 0> no_numbers;
    std::cout << "numbers.empty(): " << numbers.empty() << '\n';
    std::cout << "no_numbers.empty(): " << no_numbers.empty() << '\n';

    Buffer<char, 16> letters = {
      'D','o',' ','n','o','t',' ','a','n','s','w','e','r','!','!','!'
    };
    if (!letters.empty())
    {
        std::cout << "The first character is: " << letters.front() << '\n';
        std::cout << "The last character is: " << letters.back() << '\n';
    }
    std::cout << letters << '\n';


    try //填空
    {
        int k = 0;
        while (true)
            std::cout << letters[k++];
    }

    catch(BufferIndexError ex)
    {
        std::cout << "\nBuffer index is out of range: " << ex.getIndex() << std::endl;
    }
}



进行运算符重载有2种方式。

第一种:将运算符重载放在全局函数,这种方式的函数参数,至少有一个是我们自定义类型,不然就改变运算符的本来的意义了。

第二种:将运算符重载放在自定义class类中,这种方法方便访问类中的私有成员。第一种如果要频繁的访问类中的私有成员,可以使用将其作为类的友元函数。

友元函数说明
如果一个函数要频繁的访问类的私有成员,必须通过方法进行调用,这样会增加函数调用压栈出栈的开销,我们可以将这个函数定义为类的友元函数,这样就函数可以无私处的访问的类的私有成员了。

友元函数定义类的内部,一般是先声明后定义,和普通函数声明一样,不过在前面加一个friend 关键字。

运算符重载函数的参数
如果在全局函数进行运算符重载,那么所有的参数都必须作为函数参数。

如果是在类中进行运算符重载,函数中自动会把运算符操作的对象作为this指针传入的函数中,所以参数会少一个。如果我们要对传送的参数进行修改,如果是的c话只能传指针,c++为了更方便我们开发,添加了引用,一般我们使用引入传递。如果不是引用传递 修改只会对参数副本进行修改不会影响原对象。

运算符重载函数的返回值
返回值应该根据这个运算符运算之后的结果来确定。打个比方比如前置运算符++,可以++++a吧,那么返回值一定可以在原来的基础上继续进行改变,这样的返回值我们一般返回引用。就好比 我们重载<<运算符 返回的是ostream的引用 这样我们就可以连续使用 << 操作符了。