C 中的模板类和功能过载

Template Classes in C++ and Function Overloading

本文关键字:功能      更新时间:2023-10-16

我正在使用c 中的模板和类练习。我的目标是为Deque编写模板类。它将具有" insert_head"," insert_tail"," remove_tail"answers"删除头"的功能,以及使用" cout"打印的功能。另外," ="运算符必须能够将类的一个实例复制到另一个实例。这是我当前的代码:

#ifndef DEQUE_H
#define DEQUE_H
template <typename T>
class Deque {
public:
    Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity) 
    {}
    Deque(Deque & d) : x_(d.x()), size_(d.size()), capacity_(d.capacity()) {}

std::ostream & operator<<(std::ostream & cout) {
    cout << '[';
    if (size_ > 0) {
        for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
            std::cout << *(x_ + i) << ',';
        }
        cout << *(x_ + (size_ - 1)* sizeof(T));
    }
    cout << ']';
    return cout;
}
Deque operator=(Deque d) {
    Deque dq(d);
    return dq;
}
void print_test() {
    std::cout << '[';
    if (size_ > 0) {
        for (int i = 0; i < (size_ - 1)* sizeof(T); i += sizeof(T)) {
            std::cout << *(x_ + i) << ',';
        }
        std::cout << *(x_ + (size_ - 1)* sizeof(T));
    }
    std::cout << ']';
}
int * x() {
    return x_;
}
int size() {
    return size_;
}
int capacity() {
    return capacity_;
}
bool is_empty() {
    return size_ == 0;
}
void insert_tail(T tail) {
    if (size_ < capacity_) {
        *(x_ + sizeof(T) * size_) = tail;
        size_++;
    } else {
        // throw overflow
    }
}
T remove_tail() {
    if (size_ > 0) {
        T ret = *(x_ + sizeof(T) * (size_ - 1));
        std::cout << ret;
        size_--;
        return ret;
    } else {
        // throw underflow
    }
}
void insert_head(T head) {
    if (size_ > 0 && size_ < capacity_) {
        for (int i = (size_ - 1) * sizeof(T); i < 0; i -= sizeof(T)) {
            *(x_ + i + sizeof(T)) = *(x_ + i);
        }
    }
    if (size_ < capacity_) {
        *x_ = head;
        size_++;
    } else {
        // throw overflow
    }
}
T remove_head() {
    if (size_ > 0) {
        T ret = *x_;
        for (int i = sizeof(T); i < size_* sizeof(T); i += sizeof(T)) {
            *(x_ + i - sizeof(T)) = *(x_ + i);
        }   
        size_--;
        return ret;
    } else {
        // throw underflow
    }
}
private:
    T * x_;
    int size_;
    int capacity_;
};
#endif

这是我使用该类的测试代码:

#include <iostream>
#include "Deque.h"
int main(int argc, char const *argv[])
{
    Deque< int > dq;

    dq.insert_head(1);
    // dq.insert_head(2); // adding head when not empty causes bug
    dq.insert_tail(3);
    dq.insert_tail(4);
    dq.insert_tail(5);
    dq.print_test(); std::cout << std::endl;
    // std::cout << dq; // '<<' not overloaded properly'
    std::cout << dq.remove_head() << " head removedn";
    // int x = dq.remove_head(); // seg faults when assigning returned value to a variable 
    dq.insert_tail(2);
    dq.print_test();
    std::cout << std::endl;
    Deque< int > dq1(dq);
    Deque< int > dq2;
    // dq2 = dq1; // '=' not overloaded properly
    return 0;
}

我的四个问题中的每一个都在我的测试文件中注释的代码中,这是一个进一步的解释:

  1. 当" dq.insert_head(2)"被调用时,DQ不是空的(size> 0),我尝试将Deque中的所有其他元素移到一个位置上,以便我可以在此处插入新值,有一个问题,元素没有被移开。

  2. " std :: cout&lt;&lt; dq"不像应该打印DQ。该代码与" print_test()"方法非常相似,但是当我运行程序时,我会收到错误"对操作员&lt;&lt;"。这是因为它是模板类吗?还是我做的其他完全错误的事情?

  3. 试图从deque上卸下头部或尾巴时,我正在尝试返回删除的值。在未注释的代码行中,返回的值按应有的打印,但是以下代码行会导致SEG故障。是因为我试图将模板Varabale分配给整数变量吗?

  4. 我的最后一个问题是'='操作员没有将类的一个实例复制到另一个实例。我的目标是创建一个类的新实例,然后返回该实例(如您在" Deque Operator =(Deque D)"中看到的),但这并不能正如我希望的那样起作用。使用模板类超载" ="函数的最佳方法是什么?

感谢您的帮助,对这些问题的任何答案都非常感谢。

您的所有功能都有问题:

 Deque(int size = 0, int capacity = 1000) : size_(size), capacity_(capacity) {}
  • 如果允许指定大小,则必须为这些项目分配和初始化内存。您只能指定容量。
  • x_不初始化。

假设您想要固定容量,那么您的构造函数应为:

Deque(int capacity = 1000) 
    : size_(0)
    , x_(new T[capacity])
    , capacity_(capacity) 
{
}

,即使那是一个简化的版本,因为它将称为所有可能效率低下的项目构造函数,并且要求T具有可访问的默认构造函数。

现在,用于复制构造函数:

  • 复制构造函数应进行深层复制。否则,您的程序(可能)在删除您完成的第一个Deque之后崩溃,因为删除项目两次是未定义的行为。
  • 原型应进行恒定参考,如以下内容:Deque(const Deque &other);

代码看起来与此相似:

Deque(const Deque &other)
    : capacity_(other.capacity_)
    , x_(new T[other.capacity_])
    , size_(other.size_)
{
    for (int i = 0; i != size_; ++i)
    {
        x_[i] = other.x_[i];
    }
}

对于<<,原型应为:

friend std::ostream & operator<<(std::ostream &cout, const T &data)

假设在班级内声明它可以访问私有字段。您需要传递操作员工作的数据。

对于分配操作员,类似的事情可能有效:

Deque& operator=(const Deque &other)
{
    // Use swap idiom...
    Deque tmp(other);
    // Swap pointers so old x_ get destroyed...
    T *old_x = x_;
    x_ = tmp.x_;
    tmp.x_ = old_x;
    // Usually one would use std::swap. 
    // Here as tmp get destroyed, it is not strictly to swap capacity_ and size_.
    capacity_ = tmp.capacity_;
    size_ = tmp.size_;
}

现在用于x()函数: - 如果您进行队列,则可能不想曝光数据,因此应删除该功能。 - 如果保留,则该功能应为const,并将指针返回到预期功能的t: T *x() const;

sizecapacityis_empty都应是const成员函数。

insert_tailremove_tail问题已在其他人的评论中解释(特别是无关紧要的sizeof)。

insert_headremove_head的类似问题。此外,复制现有项目的代码可以在私人功能中重构以遵循干燥原则并避免代码重复。

您的第一个问题的答案是删除sizeof(T),因此您最终会得到此

    for (int i = (size_ - 1); i > 0; i --) {
        *(x_ + i + 1) = *(x_ + i);
    }

第二个问题的答案是将<<超载的声明更改为friend std::ostream & operator<<(std::ostream & x, Deque n)并初始化班级外的身体。

第三个问题的答案是,您无法返回一个int指针,这可能指向T的不同内存位置。

第四个问题的答案是执行以下操作:

Deque& operator=(const Deque& d) {
    x_ = d.x_; // Deep copy
    size_ = d.size_;
    capacity_ = d.capacity_;
    return *this;
}