You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++中如何用同一变量名存储不同类型的CSV读取数据?

C++ CSV读取类的统一数据变量解决方案

问题描述

我正在编写一个C++程序读取CSV文件,已实现std::string * readdatastr()和double * readdatalf()两个函数,分别用于将文件中的字符串型、双精度浮点型数据存入矩阵,并封装在readcsv类中:

class readcsv{
    public:
        int nrows;
        int ncols;
        std::string * datastr;
        double * datalf;

        void getdim(int * nrows, int * ncols){
            //function to get column and row number of the file
        }
        std::string * readdatastr(FILE * filept, int nrows, int ncols){
            //function to read data if data is std::string
        }
        double * readdatalf(FILE * filept, int nrows, int ncols){
            //function to read data if data is double
        }
        readcsv(FILE * filept, bool isstr, int nrows, int ncols){
            if(isstr){
                datastr=new std::string[nrows*ncols];
                datastr=readdatastr();
            }else{
                datalf=new double[nrows*ncols];
                datalf=readdatalf();
            }
        }
};

当前实现可正常运行,但存储数据的变量名因数据类型不同分为datastr和datalf,使用繁琐且后续易引发问题。希望实现统一变量名,或得到单一类型对应的数据集。


解决方案

方法1:模板类(推荐,类型安全且无冗余)

通过模板类让类的行为随类型参数变化,用统一的变量名data存储不同类型数据,同时避免代码重复。

#include <string>
#include <cstdio>
#include <type_traits>

template<typename T>
class readcsv {
public:
    int nrows;
    int ncols;
    T* data;

    void getdim(int* nrows, int* ncols) {
        // 实现获取CSV行列数的逻辑
    }

    // 通用读取声明,通过特化实现不同类型逻辑
    T* readdata(FILE* filept, int nrows, int ncols);

    readcsv(FILE* filept, int nrows, int ncols) : nrows(nrows), ncols(ncols) {
        data = readdata(filept, nrows, ncols);
    }

    ~readcsv() {
        delete[] data;
    }

    // 禁用拷贝构造与赋值,避免内存泄漏
    readcsv(const readcsv&) = delete;
    readcsv& operator=(const readcsv&) = delete;
};

// 特化std::string类型的读取逻辑
template<>
std::string* readcsv<std::string>::readdata(FILE* filept, int nrows, int ncols) {
    std::string* result = new std::string[nrows * ncols];
    // 这里实现CSV字符串数据的读取逻辑
    return result;
}

// 特化double类型的读取逻辑
template<>
double* readcsv<double>::readdata(FILE* filept, int nrows, int ncols) {
    double* result = new double[nrows * ncols];
    // 这里实现CSV浮点数据的读取逻辑
    return result;
}

使用方式:

FILE* fp = fopen("data.csv", "r");
int rows = 0, cols = 0;
// 先调用getdim获取行列数

// 读取字符串型数据
readcsv<std::string> str_reader(fp, rows, cols);
std::string* str_data = str_reader.data;

// 读取浮点型数据
readcsv<double> double_reader(fp, rows, cols);
double* double_data = double_reader.data;

方法2:使用std::variant(单实例支持多类型)

如果需要在同一个类实例中兼容两种数据类型,可使用C++17引入的std::variant,用单一变量存储不同类型的指针。

#include <string>
#include <cstdio>
#include <variant>
#include <functional>

class readcsv {
public:
    int nrows;
    int ncols;
    std::variant<std::string*, double*> data;

    void getdim(int* nrows, int* ncols) {
        // 实现获取行列数的逻辑
    }

    std::string* readdatastr(FILE* filept, int nrows, int ncols) {
        std::string* result = new std::string[nrows * ncols];
        // 字符串读取逻辑
        return result;
    }

    double* readdatalf(FILE* filept, int nrows, int ncols) {
        double* result = new double[nrows * ncols];
        // 浮点读取逻辑
        return result;
    }

    readcsv(FILE* filept, bool isstr, int nrows, int ncols) : nrows(nrows), ncols(ncols) {
        data = isstr ? readdatastr(filept, nrows, ncols) : readdatalf(filept, nrows, ncols);
    }

    ~readcsv() {
        // 遍历variant释放对应类型的内存
        std::visit([](auto* ptr) { delete[] ptr; }, data);
    }

    // 禁用拷贝构造与赋值
    readcsv(const readcsv&) = delete;
    readcsv& operator=(const readcsv&) = delete;
};

使用方式:

readcsv reader(fp, true, rows, cols);
if (std::holds_alternative<std::string*>(reader.data)) {
    std::string* str_data = std::get<std::string*>(reader.data);
    // 使用字符串数据
} else {
    double* double_data = std::get<double*>(reader.data);
    // 使用浮点数据
}

方法3:基类+派生类(多态实现统一接口)

通过多态定义统一的基类接口,不同数据类型对应不同派生类,实现数据访问的统一。

#include <string>
#include <cstdio>

class BaseCSVReader {
public:
    int nrows;
    int ncols;

    BaseCSVReader(int nrows, int ncols) : nrows(nrows), ncols(ncols) {}
    virtual ~BaseCSVReader() = default;

    // 统一数据访问接口
    virtual std::string get_string(int idx) const = 0;
    virtual double get_double(int idx) const = 0;
};

class StringCSVReader : public BaseCSVReader {
public:
    std::string* data;

    StringCSVReader(FILE* filept, int nrows, int ncols) : BaseCSVReader(nrows, ncols) {
        data = new std::string[nrows * ncols];
        // 字符串读取逻辑
    }

    ~StringCSVReader() override {
        delete[] data;
    }

    std::string get_string(int idx) const override {
        return data[idx];
    }

    double get_double(int idx) const override {
        return std::stod(data[idx]); // 字符串转浮点
    }
};

class DoubleCSVReader : public BaseCSVReader {
public:
    double* data;

    DoubleCSVReader(FILE* filept, int nrows, int ncols) : BaseCSVReader(nrows, ncols) {
        data = new double[nrows * ncols];
        // 浮点读取逻辑
    }

    ~DoubleCSVReader() override {
        delete[] data;
    }

    std::string get_string(int idx) const override {
        return std::to_string(data[idx]); // 浮点转字符串
    }

    double get_double(int idx) const override {
        return data[idx];
    }
};

使用方式:

BaseCSVReader* reader;
if (is_str_type) {
    reader = new StringCSVReader(fp, rows, cols);
} else {
    reader = new DoubleCSVReader(fp, rows, cols);
}

// 通过统一接口访问数据
std::string str_val = reader->get_string(0);
double double_val = reader->get_double(0);

delete reader;

内容的提问来源于stack exchange,提问作者Giacomo Marcon

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 11:36:07