【问题标题】:c++ - Checking if an Object is in empty statec++ - 检查对象是否处于空状态
【发布时间】:2016-07-26 22:51:29
【问题描述】:

我需要检查我的对象Course 是否处于安全的空状态。

这是我失败的尝试:

const bool Course::isEmpty() const {
        if (Course() == nullptr) {

            return true;
        }
        else {
            return false;
        }

    }

构造函数:

Course::Course() {
        courseTitle_ = new char[21]; // name
        courseTitle_ = '\0';
        credits_ = 0;//qtyNeeded
        studyLoad_ = 0;//quantity


        strcpy(courseCode_, "");//sku

    }
    Course::Course(const char* courseCode, const char* courseTitle, int credits , int studyLoad ) {
        strcpy(courseCode_, courseCode);
        courseTitle_ = new char[21];
        strcpy(courseTitle_, courseTitle);
        studyLoad_ = studyLoad;
        credits_ = credits;
    }

显然,执行 course() == nullptr 并不能真正检查对象是否处于安全的空状态,如果单个变量设置为 0,则检查它们在我的程序中也不起作用。我需要检查整个对象是否设置为安全的空状态。

编辑:你们中的一些人在问我的 empty() 函数应该使用什么。有一个测试器可以测试我的 isEmpty() 是否正常工作。

bool isEmptyTest0() {
    // empty test
    sict::Course c0;
    return c0.isEmpty();
}

bool isEmptyTest1() {
    // empty test
    sict::Course c0("", "title", 3, 3);
    return c0.isEmpty();
}

bool isEmptyTest2() {
    // empty test
    sict::Course c0("code", "", 3, 3);
    return c0.isEmpty();
}

bool isEmptyTest3() {
    // empty test
    sict::Course c0("code", "title", -1, 3);
    return c0.isEmpty();
}

bool isEmptyTest4() {
    // empty test
    sict::Course c0("code", "title", 3, -1);
    return c0.isEmpty();
}

bool regularInitTest() {
    // regular
    sict::Course c5("OOP244", "Object-Oriented Programming in C++", 1, 4);
    return (!c5.isEmpty()
        && !strcmp("OOP244", c5.getCourseCode())
        && !strcmp("Object-Oriented Programming in C++", c5.getCourseTitle())
        && (c5.getCredits() == 1)
        && c5.getStudyLoad() == 4
        );
}

请注意,在regularInitTest() 中,我的赋值运算符工作正常,但它永远不会通过!c5.isEmpty(),因为它失败了。希望我解释正确。

【问题讨论】:

  • 定义“安全空状态”
  • 我猜if (Course() == nullptr) 中的括号有问题。您构造一个空的 Course 对象,然后再次测试 nullptr。我不太确定你打算做什么,但可能不是这个。
  • courseTitle_ = '\0'; 应该是 courseTitle_[0] = '\0';。您正在用 char 文字的地址覆盖 new char 数组的地址。这充其量会导致内存泄漏,然后可能会导致分段错误。
  • @andirew1990 C++ 不是 Java、C 或 JavaScript。您还不了解 C++ 中的事情是如何完成的。造成这种情况的主要原因之一是“在线教科书”很糟糕。你不想解决自己的问题。相反,您想退后一步,正确地学习 C++。
  • 对我来说,isEmpty 似乎应该测试有效状态。前四个测试每个都传递一个无效值作为构造函数参数之一,并期望一个“坏/空”的课程对象。

标签: c++ object state


【解决方案1】:

很可能这是您应该做的以使测试通过。

在第二个(4 参数)构造函数中,对输入进行一些检查,例如检查credits 是否为正。请检查所有参数以查找您可以想象的所有可能错误,包括 isEmptyTest0..4 中的错误。如果出现错误,请以与第一个(0 参数)构造函数相同的方式初始化对象。如果没有错误,则从参数初始化数据成员。

这里是如何实现isEmpty 方法:如果对象的所有数据成员都具有空/零/默认值(由第一个(0 参数)构造函数初始化),它应该返回 true。

安全的空状态这个概念本身仍然没有意义,但教授试图教授的概念确实有道理。我将尝试在这里总结我的理解。构造函数可以接收无效参数,基于这些参数无法初始化有意义且有效的对象。程序员应该在程序的任何地方添加用于错误检查和处理的代码,包括构造函数。有多种方法可以在构造函数中进行输入验证和错误处理,例如1. 抛出异常; 2. 用错误信息中止整个程序; 3. 将对象初始化为特殊的无效状态; 4. 将对象初始化为特殊的空状态。 (这也是一种选择,但强烈不推荐: 5. 保持对象的一些数据成员未初始化。)这些方法中的每一种都有利有弊。在这个作业中,教授希望你实现#4。请参阅我的答案中的第二段如何做到这一点。

当教授要求安全的空状态时,他的意思很可能是您应该在构造函数中进行输入验证,并且如果在执行 #4 而不是 #5 时出现错误。

【讨论】:

  • 试过了,没有成功。它仍然失败了 regularInitTest() paste.ofcode.org/34pfSV9Jmdg9PUgjVC8XP8k
  • 感谢您发布代码!你的做法与我的建议不同。我建议这样做:即使只有 1 个参数有错误,所有参数也应设置为空。如果修复此问题后仍然失败,并且您无法弄清楚原因,我认为您应该在 StackOverflow 上发布一个单独的问题,询问“为什么 regularInitTest 失败?”。确保在新问题中包含所有 C++ 源文件(不仅仅是 sn-ps),以便其他人可以编译和运行您的代码。
  • 本课程的目标之一是让您练习调试和修复代码。为了最大限度地发挥它,你应该主动思考:“有什么方法可以让这些测试成功吗?”,想出很多想法,尝试所有的方法,如果没有一个可行,然后才提出问题,并在问题中包含您迄今为止尝试过的所有内容以及它们为什么以及如何不起作用。如果是您(而不是试图回答您问题的人)花费了最多的时间和精力,那么您就做对了。
【解决方案2】:

我同意 pts 的观点,即 安全的空状态 定义不明确。

在阅读 cmets 后,我觉得缺少的原则是 Resource Acquisition Is Initialization (RAII)。构造函数是一个事务,在某种程度上:你得到一个

  • 一个有效的对象,或
  • 异常。

Valid 这里是由类定义的。通常这意味着传递的参数被合并到对象中,并且所有需要的资源都已成功分配和/或找到。

中止程序很少是一种选择,而返回错误(从构造函数)永远不是。构造无效对象通常只在禁止异常的环境中进行。

有一种特殊情况:默认构造函数。有时需要“制作一个空的”东西,以便稍后完全初始化。

考虑std::string。它可以用一个值来构造,如果无法分配内存则抛出异常。或者它可以在没有值的情况下构造,然后分配一个。您的类可能类似,在这种情况下,safe empty 仅表示用户在调用“init”函数时乐于破坏的状态。您不必测试每个成员变量;您只需要检查仅对于完全初始化的对象才正确的内容。

然后是“有效”的问题。 “空”对象可以“初始化”,但不能使用。在完全初始化之前,它不是“有效”的,无论是在构造时,还是通过带有默认构造函数和后续“init”的两步。

测试一个对象是否“有效”有一个被广泛接受的习惯用法:用户定义的到void *的转换:

...
public:
  operator void*() { return is_valid()? this : nullptr; }
...

其中is_valid() 可能是一个私有函数。有了这个,用户就可以测试他的实例化对象:

class A;
A foo();
...
if (!foo) { foo.open(...); }

我知道我没有准确地回答你的问题。我希望我提供了一些背景知识,让您自己回答起来更容易。

【讨论】:

    猜你喜欢
    • 2023-03-03
    • 1970-01-01
    • 2021-05-24
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 2020-01-11
    • 2019-12-10
    • 1970-01-01
    相关资源
    最近更新 更多