【问题标题】:Abstract Base class not returning correctly抽象基类未正确返回
【发布时间】:2013-10-12 09:10:52
【问题描述】:

我还没有完全理解抽象基类。这是我为我的作业创建的,它似乎主要工作,除了它不会返回通过派生类添加的任何内容。每当我选择 hasDMA 或 lacksDMA 时,我都不会得到颜色或样式返回的结果。

Main.cpp

#include <iostream>
#include <conio.h>
#include "DMA.h"

using namespace std;

const int RECORDS = 1;
const int LEN = 40;

int main()
{
    ABC * p_records[RECORDS];

    int i;
    for (i = 0; i < RECORDS; i++)
    {
        char temp[LEN];
        int temprate;
        char choice;

        cout << "\nEnter label name: ";
        cin.getline(temp, LEN);
        cout << "Enter Rating: ";
        cin >> temprate;

        cout << "Enter 1 for lacksDMA or 2 for hasDMA: ";
        while (cin >> choice && (choice != '1' && choice != '2'))
            cout << "Enter 1, 2: ";
        if (choice == '1')
        {
            char tempcolor[LEN];
            cout << "Enter the color: ";
            cin.getline(tempcolor, LEN);
            p_records[i] = new lacksDMA(temp, temprate, tempcolor);         
        }
        else
        {
            char tempstyle[LEN];
            cout << "Enter the style: ";
            cin.getline(tempstyle, LEN);
            p_records[i] = new hasDMA(tempstyle, temp, temprate);           
        }
        while (cin.get() != '\n')
            continue;
    }
    cout << endl;
    for (i = 0; i < RECORDS; i++)
    {
        p_records[i]->View();
        cout << endl;
    }

    for (i = 0; i < RECORDS; i++)
    {
        delete p_records[i];
    }

    cout << "\nPress any key to continue...";
    cin.sync();
    _getch();

    return 0;
}

DMA.cpp

#include "DMA.h"

using namespace std;


ABC::ABC(const char * l, int r)
{
    label = new char [strlen(l) + 1];
    strcpy(label, l);
    rating = r;
}

ABC::ABC(const ABC & rs)
{
    label = new char[strlen(rs.label) + 1];
    strcpy(label, rs.label);
    rating = rs.rating;
}

ABC::~ABC()
{   
}

ABC & ABC::operator=(const ABC & rs)
{
    if (this == &rs)
        return *this;
    delete [] label;
    label = new char[strlen(rs.label) + 1];
    strcpy(label, rs.label);
    rating = rs.rating;
    return *this;
}

ostream & operator<<(ostream & os, const ABC & rs)
{
    rs.View();
    return os;
}

void ABC::View() const
{
    cout << "\nLabel: " << label << endl;
    cout << "Rating: " << rating << endl;
}

baseDMA::baseDMA(const char * l, int r) : ABC(l,r)
{
}

lacksDMA::lacksDMA(const char * l, int r, const char * c) : ABC(l,r)
{
    strncpy(color, c, 39);
    color[39] = '\0';
}

lacksDMA::lacksDMA(const ABC &rs, const char * c) : ABC(rs)
{
    strncpy(color, c, 39);
    color[39] = '\0';
}

void lacksDMA::View() const
{
    ABC::View();
    cout << "Color: " << color << endl; 
}

hasDMA::hasDMA(const char * s, const char * l, int r) : ABC(l,r)
{
    style = new char [strlen(s) + 1];
    strcpy(style, s);   
}

hasDMA::hasDMA(const char * s, const ABC & rs) : ABC(rs)
{
    style = new char [strlen(s) + 1];
    strcpy(style, s);
}

hasDMA::hasDMA(const hasDMA & hs) : ABC(hs)
{
    style = new char [strlen(hs.style) + 1];
    strcpy(style, hs.style);
}

hasDMA::~hasDMA()
{
    delete [] style;
}

void hasDMA::View() const
{
    ABC::View();
    cout << "Style: " << style << endl;
}

DMA.h

#ifndef DMA_H_
#define DMA_H_
#include <iostream>

using namespace std;

// Abstract Base Class
class ABC
{
private:
    char * label;
    int rating;
public:
    ABC(const char * l = "null", int r = 0);
    ABC(const ABC & rs);
    virtual ~ABC() = 0;
    virtual ABC & operator=(const ABC & rs);
    virtual void View() const;
    friend ostream & operator<<(ostream & os, const ABC & rs);
};

// Former Base Class Using DMA
class baseDMA: public ABC
{
private:

public:
    baseDMA(const char * l = "null", int r = 0);
};

// derived class without DMA
// no destructor needed
// uses implicit copy constructor
// uses implicit assignment operator
class lacksDMA : public ABC
{
private:
    char color[40];
public:
    lacksDMA(const char * l = "null", int r = 0, const char * c = "blank");     
    lacksDMA(const ABC & rs, const char * c);
    virtual void View() const;
};

// derived class with DMA
class hasDMA : public ABC
{
private:
    char * style;
public:
    hasDMA(const char * s = "none", const char * l = "null", int r = 0);
    hasDMA(const char * s, const ABC & rs);
    hasDMA(const hasDMA & hs);
    ~hasDMA();
    hasDMA & operator = (const hasDMA & rs);
    void View() const;
};

#endif

【问题讨论】:

  • 这代码太多了。请发布您认为问题所在的部分。
  • std::stringstd::vector 怎么样???您的代码充满了动态分配......上帝帮助那些必须调试它的人。
  • 我没有看到代码有任何问题(除了你应该在ABC::~ABC() 中使用delete[] label,或者最好让它成为std::string)。确保您的代码与此处发布的代码相同。此外,描述示例输入、预期输出和实际输出。
  • 确保在您的代码中 ABC::View 确实声明为 virtual,并且该关键字 const 要么在所有 3 个函数签名中,要么不在其中。这是最重要的部分。
  • 当我运行它并输入标签测试,评级为 10,缺少 DMA 选择 1,然后它会询问它应该的颜色,然后我输入红色。在那一点上,一切似乎都很顺利。但是,当显示记录时,标签和评级是正确的,但没有显示任何颜色。它只显示颜色:

标签: c++ abstract abc


【解决方案1】:

在您所说的 cmets 中,显示了字符串“Color:”,但不显示示例输入“red”。因为显示了“颜色:”,所以这不是代码的抽象/虚拟部分失败的问题(否则即使“颜色:”也不会显示)。

失败在输入中。当您读取“1”或“2”的选择时,您只读取了一个字符,但用户实际上也输入了额外的新行,因此下一个cin.getline 将使用这个额外的新行并返回一个空字符串。对于所有输入,您应该坚持使用cin.getline,即使输入只是一个字符,即使输入是一个数字。永远不要使用cin &gt;&gt;,自己处理输入中的错误,比将operator&gt;&gt;getline 混合在一起,然后在它们不能很好地配合使用时处理所有边界情况要容易。

虽然这不是答案的一部分,但这里有一些一般性建议:

1) 在 C++ 中,尽可能避免使用new char[x]。对字符串使用std::string,在std::string 不够好的极少数情况下使用std::vector&lt;char&gt;

1b) 你忘了delete [] labelABC 的析构函数中。如果是std::string,您就不必担心这些事情。

2) 可以在源文件 (.cpp) 中使用 use namespace std,并且只在所有 #includes 之后,但不要在头文件 (.h) 中使用它。绝不!在头文件中使用全名(如std::string 而不是string

编辑:因此,需要一些代码示例。就像我说的,坚持cin.getline,避免operator&gt;&gt;,即使输入只是一个字符,即使输入是整数:

cin &gt;&gt; temprate; 行替换为:

    cin.getline(temp, LEN);
    temprate = strtol(temp, NULL, 10);

替换两行while循环

    while (cin >> choice && (choice != '1' && choice != '2'))
        cout << "Enter 1, 2: ";

这些for 行在中间有出口(我最喜欢的无限循环方式):

    for (;;)
    {
        cin.getline(temp, LEN);
        choice = temp[0];

        if (choice == '1' || choice == '2')
            break;

        cout << "Enter 1, 2: ";
    }

【讨论】:

  • 所以基本上当我要求输入 hasDMA 或缺少DMA 时,它会在下一个问题中保留一个空行?
  • 是的,cin &gt;&gt; choice 部分代码不使用输入中的换行符。
  • 即使我将选择的输入更改为整数,它仍然无法正常工作。我似乎无法弄清楚如何在不保留空白的情况下获得此输入。
  • 非常感谢。抱歉,我在示例方面做得更好,这虽然很直接,但帮助很大。我现在明白了使用 getline 而不是 cin >> 的意思。看到 temp 被用作其他项目的存放位置,尽管我确实必须将标签的输入更改为 tempname 并让 temp 使用 strncpy 将其复制过来。再次感谢
  • @user2849274 不客气。如果这是一个正确的答案,那么您应该通过单击左侧的白色复选标记来标记它。
猜你喜欢
  • 2011-12-16
  • 2019-08-31
  • 2011-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-21
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多