【问题标题】:What's wrong with this class?这堂课有什么问题?
【发布时间】:2011-10-22 23:54:23
【问题描述】:

我认为问题出在 main() 中,但编译得很好,但我没有得到任何输出。我想也许它没有正确初始化,因为在调试模式下它说
"myCharQ {item=0x0018fa00 "ÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ̺yâpú" front=-858993460 rear=-858993460 ...}"

您将如何重写它以使其正确?我刚开始上课,所以任何帮助都会很有用。

以下是一个基于Array的Queue类

#include <iostream>
#include <cstdlib>
using namespace std;

const int MaxQueueSize = 10; // Queue Struct can hold up to 10 char.
typedef char ItemType; // the queue's data type is char

class CPPQueue
{
public:
    CPPQueue();
    ItemType item[MaxQueueSize];
    void initQueue(CPPQueue q);
    bool IsEmpty(CPPQueue q);
    bool IsFull(CPPQueue q);
    void Enqueue(CPPQueue q, ItemType newItem);
    void PrintQ(const CPPQueue q);
    void PrintQueueInfo(CPPQueue myQ);
    ItemType Dequeue(CPPQueue q);
private:
    int front, rear;
    int count;
};
CPPQueue::CPPQueue() 
{
    int front, rear, count = 0;
}
void CPPQueue::initQueue(CPPQueue q)
{
    q.front = q.rear = q.count = 0;
}
bool CPPQueue::IsEmpty(CPPQueue q)
{
    return (q.count == 0);
}
bool CPPQueue::IsFull(CPPQueue q)
{
    return (q.count == MaxQueueSize);
}
void CPPQueue::Enqueue(CPPQueue q, ItemType newItem)
{
    if(q.count == MaxQueueSize)
    {
        cerr << "Error! Queue is full, cannot enqueue item.\n" << endl;
        exit(1);
    }
    q.item[q.rear] = newItem;
    q.rear++;
    if (q.rear == MaxQueueSize)
    {
        q.rear = 0; // adjustment for circular queue
    }
    q.count++;
}
ItemType CPPQueue::Dequeue(CPPQueue q)
{
    ItemType theItem;
    if(q.count == 0)
    {
        cerr << "Error! Queue is empty, cannot dequeue item.\n" << endl;
        exit(1);
    }
    theItem = q.item[ q.front ];
    q.front++;
    if (q.front == MaxQueueSize)
    {
        q.front = 0; // adjustment for circular queue
    }
    q.count--;
    return theItem;
}
// Function PrintQ() prints the contents of the queue without changing
// the queue. Printing starts at the "front" index and stops before we
// get to the "rear" index. A decrementing counter controls the loop.
//
void CPPQueue::PrintQ(const CPPQueue q)
{
    int i;
    int qindex = q.front;
    for(i = q.count; i > 0; i--)
    {
        cout << q.item[qindex] ;
        qindex = (++qindex) % MaxQueueSize; // adjustment for circular queue
        if(i > 1)
            cout << ", ";
    }
}
// Helper function for the main program below.
void CPPQueue::PrintQueueInfo(CPPQueue myQ)
{
    cout << "The queue contains: ";
    PrintQ(myQ);
    cout << endl;
}
int main()
{
    CPPQueue myCharQ;// queue holds characters
    char ch; // char dequeued
    myCharQ.initQueue(myCharQ);
    myCharQ.Enqueue(myCharQ, 'a'); myCharQ.PrintQueueInfo(myCharQ);
    myCharQ.Enqueue(myCharQ, 'b'); myCharQ.PrintQueueInfo(myCharQ);
    myCharQ.Enqueue(myCharQ, 'c'); myCharQ.PrintQueueInfo(myCharQ);

    ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);
    ch = myCharQ.Dequeue(myCharQ); myCharQ.PrintQueueInfo(myCharQ);

    myCharQ.Enqueue(myCharQ, 'e');
    myCharQ.Enqueue(myCharQ, 'f'); myCharQ.PrintQueueInfo(myCharQ);
    myCharQ.Enqueue(myCharQ, 'g'); myCharQ.PrintQueueInfo(myCharQ);
    cout << endl;
    // print the dequeued characters
    while(!myCharQ.IsEmpty(myCharQ))
    {
        ch = myCharQ.Dequeue(myCharQ);
        cout << ch << " ";
    }
    cout << endl << endl;
    return 0;
}

【问题讨论】:

  • 注意像IsEmpty这样的成员函数不应该带任何参数。它们是类的非静态成员,因此它们总是作用于调用它们的对象。
  • 这是一个很好的参考 - cplusplus.com/reference/iostream/cout -

标签: c++ class


【解决方案1】:

您永远不会初始化 member 变量 front、rear 和 count。通过再次声明具有相同名称的变量,您可以在构造函数中隐藏它们。删除int 并分配它们(尽管这不是为什么不能正确打印值的原因,稍后会详细介绍)。实际上,也不要那样做;使用初始化列表:

CPPQueue::CPPQueue() 
  : front(0), rear(0), count(0) 
{ }

另外,为什么你有一个initQueue 函数?您已经有一个构造函数,依靠它来初始化您的实例(这不是 C!)。

接下来,像IsEmpty 这样的函数是非静态成员函数,但它们不会对当前实例进行操作。不要将队列作为参数,如果实例为空、已满等则返回。您的代码必须像这样使用:

Queue q;
q.IsEmpty(q);

真奇怪。您的所有成员函数都以这种方式运行。当您可以使用成员函数时,指向当前实例的隐式指针将作为隐藏参数 (this) 传递。因此,每次调用该函数时,它都会在调用它的实例的上下文中运行。您不需要将实例作为参数。

还要意识到您的所有函数都按值获取参数。您将疯狂地创建这些队列的副本。如果您修改参数,调用者将看不到它。例如:

void CPPQueue::initQueue(CPPQueue q)
{
    q.front = q.rear = q.count = 0;
}

这基本上是无用的(除了不需要初始化函数的事实)。当您对副本进行操作时,对 q.front、q.rear 和 q.count 的更改将在该函数之外不可见。

因此,即使您的构造函数由于变量阴影而损坏,this 就是为什么您在调用 initQueue 后仍然没有打印出您期望的结果。 您正在修改副本。

至于您的实现,它一点也不健壮。您将底层数组公开给您的类的客户。这是一个坏主意。队列中的项目不应直接访问。如果我决定直接使用数组怎么办?现在你所有的状态变量都是错误的。 front、rear 和 count 都可能无效,因为我已经修改了队列的状态,而没有通过您的任何函数。

这甚至没有必要;我应该能够做的就是排队和出列项目。就是这样。这就是队列的作用。它不是一个数组,如果我想要一个数组,我会使用一个。

因此,总而言之,开始学习一门相对复杂的语言是值得称赞的。坚持下去,不要气馁,我们都必须在某个时候学习这些东西。

编辑:我必须跑步,但这里是对你的一些课程的快速重写。我已经删除了项目类型的 typedef。为什么?这是不必要的。您不会根据某个平台或其他环境变化将其更改为另一种类型,因此 typedef 只会伤害您的类的可用性。 typedef 适用于可能因某种环境原因而发生变化的事物(即 int32_t),但如果它们不能帮助您或您的代码的客户,它们只是另一件事。

class CPPQueue
{
public:
    CPPQueue();
    bool IsEmpty() const;
    bool IsFull() const;
    void Enqueue(char newItem);
    char Dequeue();
    void PrintQ() const;
    void PrintQueueInfo() const;
private:
    char item[MaxQueueSize];
    int front
    int rear;
    int count;
};

CPPQueue::CPPQueue()
  : front(0), rear(0), count(0) { }

bool CPPQueue::IsEmpty() const
{ 
    // you don't actually need the this pointer
    // here, but I included it to make it clear
    // that you are accessing the count variable
    // for the current instance of a CPPQueue
    return this->count == 0; 
}

我希望这能帮助你改写你的其余课程,现在得走了。我在不应改变CPPQueue 内部状态的函数声明中添加了const。搜索“const 正确性”以更好地了解您为什么要这样做。祝你好运!

【讨论】:

  • 非常感谢 Ed 这个精彩的帖子。只是为了巩固你所说的,(如果不是太麻烦的话)你能不能按照你的描述写这个类,以便我明白你的意思?非常感谢您的帮助
  • @EdS。非常感谢,我完全明白了!为你干杯!
【解决方案2】:

在你的构造函数中:

int front, rear, count = 0;

错了。这些是影响成员变量的局部变量。

你应该使用成员初始化器(在你的构造函数名称后加上冒号)。

另外请注意,您到处都是按值传递 - 您可能希望通过引用传递 - 查看每个函数参数并问自己:“我想要一个新的参数副本还是要引用到我传入的同一个参数(同一个内存位置)?”

CPPQueue::CPPQueue() :
  front(0), rear(0), count(0) 
{
}

注意:@OP 这是初级 C++ - 您需要阅读并掌握基础知识,否则您将遇到许多更难解决的问题。

【讨论】:

  • 谢谢,但我是新手,你能写出它的样子吗?
猜你喜欢
  • 2016-11-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-11-08
  • 2020-08-30
  • 1970-01-01
  • 1970-01-01
  • 2020-08-01
相关资源
最近更新 更多