【问题标题】:c++ function redefining (code not working - logic error)c ++函数重新定义(代码不起作用 - 逻辑错误)
【发布时间】:2019-01-16 03:12:14
【问题描述】:

我目前正在学习 c++,现在正在研究继承。 我必须制作一个常规问题类以及一个数字问题和多项选择问题的派生类。我在代码中提出问题,然后将它们一一显示给用户。然后用户回答问题,程序应该检查答案是否正确。

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

class Question {
protected:
    string text;
    string answer;
    string input;
public:
    Question(string inText, string inAnswer) {
        text = inText;
        answer = inAnswer;
    }
    Question() {
        text = "blank question";
        answer = " ";
    }
    void setQuestion(string txt) {
        text = txt;
    }
    void setAnswer(string answr){
        answer = answr;
    }
    void userAnswer(string ans) {
        input = ans;
    }
    string getAnswer() {
        return answer;
    }
    string getQuestion() {
        return text;
    }

    void displayQuestion() {
        cout << getQuestion() << endl;
    }
    void isCorrect() {
        cout << "default function" << endl;
        if (input.compare(answer) == 0)
            cout << "True" << endl;
        else
            cout << "False" << endl;
    }
};
class NumericQuestion : public Question {
protected:
    double ans;
    double inp;
public:
    NumericQuestion(string inText, double inAns) {
        text = inText;
        ans = inAns;
    }
    void userAnswer(string ans) {
        inp = stod(ans);
    }

    void isCorrect() {
        cout << "numeric function" << endl;
        if (inp == ans)
            cout << "True" << endl;
        else if ((inp - ans) <= 0.01)
        cout << "False" << endl;
        else
            cout << "False" << endl;
}
};
class MultipleChoice : public Question {
protected:
    string qA, qB, qC, qD;
public:
    MultipleChoice(string inText, string qA, string aB, string qC, string qD,         char inAnswer) {
        text = inText;
        answer = inAnswer;
    }
    void displayQuestion() {
        cout << text << endl;
        cout << "a) " << qA << "    " << "b) " << qB << endl;
        cout << "c) " << qC << "    " << "d) " << qD << endl;
    }
};

int main() {
    string ans;

    Question q1("whats 2+2", "four");
    NumericQuestion q2("2+2", 4);

    MultipleChoice q3("The Right Answer is C", "answer A", "thisisB", "thats C", "Wrong", 'c');

    Question arr[] = { q1,q2,q3};
    for (int i = 0; i < 3; i++) {
        arr[i].displayQuestion();
        cin >> ans;
        arr[i].userAnswer(ans);
        arr[i].isCorrect();
    }

getchar();
return 0;
}

没有使用来自 NumericQuestion 类的成员函数 isCorrect() 和来自 MultipleChoice 类的 displayQuestion(),而是使用了来自 Question 类的成员函数,这会导致我的代码出现逻辑错误。

【问题讨论】:

标签: c++ function class inheritance overriding


【解决方案1】:

当您将Questions 的子类按值分配给Question 的数组时,您就是slicing objects,而当您执行Question arr[] = { q1, q2, q3 }; 时。这意味着即使您的某些派生 Question 对象具有基类没有的额外成员,它们也会被分配到数组中而被截断。另一个问题是,因为 arr 被声明为包含简单的 Question 对象,编译器将假定像 arr[i].isCorrect(); 这样的调用将总是引用 Question::isCorrect(),而不是派生的方法。这里有几件事需要解决。

制作可覆盖的函数virtual:

class Question {
    ...
    virtual void isCorrect() {
        cout << "default function" << endl;
        if (input.compare(answer) == 0)
            cout << "True" << endl;
        else
            cout << "False" << endl;
    }

override它们在子类中:

class NumericQuestion : public Question {
    ...
    void isCorrect() override {
        cout << "numeric function" << endl;
        if (inp == ans)
            cout << "True" << endl;
        else if ((inp - ans) <= 0.01)
            cout << "False" << endl;
        else
            cout << "False" << endl;
    }

最后,通过将基类指针存储到Questions 来避免切片。在这里,我使用std::shared_ptr 来避免手动内存管理带来的麻烦。还出现了ranged-for loop

auto q1 = std::make_shared<Question>("whats 2+2", "four");
auto q2 = std::make_shared<NumericQuestion> q2("2+2", 4);

auto q3 = std::make_shared<MultipleChoice>("The Right Answer is C", "answer A", "thisisB", "thats C", "Wrong", 'c');

// even though q1...q3 are shared_ptrs to derived classes, they can be safely cast to shared_ptrs to the base class
std::vector<std::shared_ptr<Question>> questions { q1, q2, q3 };

for (const auto& question: questions) {
    question->displayQuestion();
    cin >> ans;
    question->userAnswer(ans);
    question->isCorrect();
}

【讨论】:

  • 我建议使用std::unique_ptr 而不是std::shared_ptr,除非您确实需要共享所有权。否则,您要为永远不会使用的引用计数付费。
  • @NathanOliver 我考虑过,但这意味着std::move-ing 将它们放入向量中,我不确定 OP 是否已准备好
  • @NathanOliver 在提问者的当前级别,引用计数的成本当然可以忽略不计。 IMO,现在引入共享指针还为时过早。这是一个非常好的答案,但您可能会放弃他的班级教授甚至可能不知道的花哨的现代 C++。
【解决方案2】:

您需要在基类中将userAnswerdisplayQuestionisCorrect 设置为虚拟。

您还需要将您的问题存储为指针(还有其他选项)以防止切片。就个人而言,我发现这样修复它更简单:

Question* arr[] = {&q1,&q2,&q3};
...
arr[i]->displayQuestion();

(您需要更改所有用法或 arr[i] 以使用箭头)

【讨论】:

    【解决方案3】:

    这里有两个问题。

    1) 基于你最后的for循环,你需要声明一些函数,比如displayQuestion()userAnswer()isCorrect()virtual

    2) 其次,将您的 arr 声明更改为 Question *arr[] = {&amp;q1, &amp;q2, &amp;q3};

    【讨论】:

    • 我必须为每个实例都这样做吗?
    • 这并没有解决arr发生的切片问题
    • @alterigel 你能详细说明一下吗?
    • 添加虚拟关键字没有帮助...我之前尝试过。又做了一次。我得到完全相同的结果
    • 也许我需要以不同的方式实现数组?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-24
    • 2017-09-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多