【问题标题】:void* is not a pointer object / casting implementationvoid* 不是指针对象/强制转换实现
【发布时间】:2016-09-13 22:08:20
【问题描述】:

从下面的代码中,我正在尝试创建一个课程评分系统。因此,它将存储作业的类型、权重和达到的成绩。我试图让它打印原始分数(这是输入的成绩,例如:“B-”或 85.50;取决于它是考试还是测验)。

我已经阅读了有关“强制转换”的信息,它应该可以解决使用void* 作为指针的问题,但我仍然不清楚如何实现它。我试过static_cast<struct Grading*>(c.gs[0])(在代码中注释掉)但它仍然返回值的地址,而不是值本身。任何帮助将不胜感激。提前致谢!

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

struct Grading{
    string name;
    int percentage;
    virtual ~Grading(){}
    virtual void* get_raw_score(){return 0;}
    void* get_adj_score(){return 0;}
};

struct Quiz:public Grading{
    string letter_grade;
    Quiz(const string title, const int weight, const string grade){
        name=title;
        percentage=weight;
        letter_grade=grade;
    }
    virtual void* get_raw_score(){return &letter_grade;}
};

struct Exam:public Grading{
    double *score = new double;
    Exam(const string title, const int weight, const double grade){
        name=title;
        percentage=weight;
        *score=grade;
    }
    virtual void* get_raw_score(){return &score;}
};

struct Project:public Grading{
    string letter_grade;
    Project(const string title, const int weight, const string grade){
        name=title;
        percentage=weight;
        letter_grade=grade;
    }
    virtual void* get_raw_score(){return &letter_grade;}
};

struct CourseWork{
    vector<Grading*> gs;
    void push_back(Grading* g){
        gs.push_back(g);
    }
    void sort_name(){}
    void sort_score(){}
};

ostream& operator<<(ostream& o,const CourseWork c){ //output the raw score here.
 //static_cast<struct Grading*>(c.gs[0]);
    o<<c.gs[0]->name<<endl<<c.gs[0]->percentage<<c.gs[0]->get_raw_score()<<endl;
    return o;
}

int main() {

    CourseWork c;

    c.push_back(new Quiz("Quiz", 5, "B-"));
    c.push_back(new Quiz("Quiz", 5, "C+"));
    c.push_back(new Quiz("Quiz", 5, "A"));
    c.push_back(new Exam("Midterm", 10, 50));
    c.push_back(new Exam("Final", 30, 85.5));
    c.push_back(new Project("Project", 5, "A-"));
    c.push_back(new Project("Project", 15, "B-"));
    c.push_back(new Project("Project", 15, "B-"));
    c.push_back(new Project("Demo", 10, "C"));

    cout << "** Showing populated data..." << endl;
    cout << c << endl << endl;;

    c.sort_name();
    cout << "** Showing sorted by name..." << endl;
    cout << c << endl << endl;

    c.sort_score();
    cout << "** Showing sorted by score..." << endl;
    cout << c << endl;

    return 0;
}

【问题讨论】:

  • 根据我所做的阅读,这是获得stringdouble 的唯一方法,因为如果作业是测验,它将是string 等级,但如果它是考试,它将是double int
  • 听起来你可能想要boost::variant
  • ^ ... 或者只是一个模板化的Grading 基类。
  • @NathanOliver 我不能使用任何外部库。这是一个分级作业,所以我只能使用标准的 c++ 库。
  • 这是作业吗?我建议您非常仔细地阅读作业,因为它可能解释了我们想要什么。我怀疑从虚函数返回void * 真的是提倡的解决方案。我建议返回string(并根据需要将数字分数转换为字符串)。

标签: c++ c++11 casting void-pointers


【解决方案1】:

与其编写一个返回void* 的函数并试图找出它实际返回的内容,您可以让该函数在所有情况下都返回一个字符串,但当它是一个数字时,只需将数字转换为一个字符串。你可以使用:

struct Grading{
    string name;
    int percentage;
    virtual ~Grading(){}
    virtual std::string get_raw_score() = 0; //make pure virtual since we only use Grading as a base class
    void* get_adj_score(){return 0;}
};

struct Quiz:public Grading{
    string letter_grade;
    Quiz(const string title, const int weight, const string grade){
        name=title;
        percentage=weight;
        letter_grade=grade;
    }
    virtual std::string get_raw_score(){return letter_grade;}
};

struct Exam:public Grading{
    double score; // this does not need to be a pointer
    Exam(const string title, const int weight, const double grade){
        name=title;
        percentage=weight;
        score=grade; // no more dereference
    }
    virtual std::string get_raw_score(){return std::stod(score);} // now the score is represented as a string
};

struct Project:public Grading{
    string letter_grade;
    Project(const string title, const int weight, const string grade){
        name=title;
        percentage=weight;
        letter_grade=grade;
    }
    virtual std::string get_raw_score(){return letter_grade;}
};

struct CourseWork{
    vector<Grading*> gs;
    void push_back(Grading* g){
        gs.push_back(g);
    }
    void sort_name(){}
    void sort_score(){}
};

ostream& operator<<(ostream& o,const CourseWork c){ //output the raw score here.
 //static_cast<struct Grading*>(c.gs[0]);
    o<<c.gs[0]->name<<endl<<c.gs[0]->percentage<<c.gs[0]->get_raw_score()<<endl;
    return o;
}

【讨论】:

  • 完成,稍微调整一下我的答案。
  • @πάνταῥεῖ 我想对此发表评论,为什么还要使用模板?你的答案现在和我的一样,但现在你有了三层层次结构,模板没有增加额外的安全性。
  • 是的,这是值得商榷的。其他属性 titleweight 也应该被分解为一个基类。
【解决方案2】:

您可以使您的基类抽象并使用模板参数而不是使用void* 指针:

struct IGrading {
     virtual const std::string get_raw_score() const = 0;
};

template<typename T>
class Grading : public IGrading {
public:
     virtual ~Grading() {}
};

std::ostream& operator<<(std::ostream& os, const IGrading& g) {
    os << g.get_raw_score();
    return os;
}

并根据需要派生您的实现以实现接口契约

class Quiz : public Grading<std::string> {
public:
     Quiz(std::string title, int weight, std::string rawScore) 
     : title_(title)
     , weight_(weight).
     , rawScore_(rawScore) {}
     virtual const std::string& get_raw_score() const {
         return rawScore_;
     }

private:
     std::string title_;
     int weight_;
     std::string rawScore_;
};

...和类似的实现:

class Exam : public Grading<double> {
public:
     Exam(std::string title, int weight, double rawScore) 
     : title_(title)
     , weight_(weight)
     , rawScore_(rawScore) {}
     virtual const std::string& get_raw_score() const {
         return std::to_string(rawScore_);
     }

private:
     double rawScore_;
};

或者有一个用于数字模板参数的通用基类实现:

template<typename T>
class NumericGrading : public Grading<T> {
protected:
    NumericGrading(T rawScore) : rawScore_(rawScore) {}
public:
     virtual const std::string& get_raw_score() const {
         return std::to_string(rawScore_);
     }

protected:
     T rawScore_;
};

Exam 推导出:

class Exam : public NumericGrading<double> {
public:
     Exam(std::string title, int weight, double rawScore) 
     : NumericGrading<double>(rawScore)
     , title_(title)
     , weight_(weight) {}
};

这将确保您的代码类型安全并避免任何奇怪且容易出错的转换操作。

CourseWork容器可以使用抽象接口:

struct CourseWork{
    vector<IGrading*> gs;
    void push_back(IGrading* g){
        gs.push_back(g);
    }
    void sort_name(){}
    void sort_score(){}
};

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-07-22
    • 2014-04-01
    • 2018-03-05
    • 1970-01-01
    • 2017-04-22
    • 2013-12-24
    • 1970-01-01
    相关资源
    最近更新 更多