Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/144.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
绑定到枚举的类成员 我可能面临一些C++类设计的问题,主要是因为我需要把数据库集成到我的系统中。我有一个基类,它有一些子类。我发现有一个名为type的成员是多余的,它是一个枚举,描述了它的子类type。范例 enum FooTypes { kFooTypeGeneric, kFooTypeA, kFooTypeB }; class Foo { public: Foo(FooTypes type):type(type){} FooTypes type; }; class FooA : public Foo { public: FooA():Foo(kFooTypeA){} }; class FooB : public Foo { public: FooB() :Foo(kFooTypeB) {} };_C++_Enums - Fatal编程技术网

绑定到枚举的类成员 我可能面临一些C++类设计的问题,主要是因为我需要把数据库集成到我的系统中。我有一个基类,它有一些子类。我发现有一个名为type的成员是多余的,它是一个枚举,描述了它的子类type。范例 enum FooTypes { kFooTypeGeneric, kFooTypeA, kFooTypeB }; class Foo { public: Foo(FooTypes type):type(type){} FooTypes type; }; class FooA : public Foo { public: FooA():Foo(kFooTypeA){} }; class FooB : public Foo { public: FooB() :Foo(kFooTypeB) {} };

绑定到枚举的类成员 我可能面临一些C++类设计的问题,主要是因为我需要把数据库集成到我的系统中。我有一个基类,它有一些子类。我发现有一个名为type的成员是多余的,它是一个枚举,描述了它的子类type。范例 enum FooTypes { kFooTypeGeneric, kFooTypeA, kFooTypeB }; class Foo { public: Foo(FooTypes type):type(type){} FooTypes type; }; class FooA : public Foo { public: FooA():Foo(kFooTypeA){} }; class FooB : public Foo { public: FooB() :Foo(kFooTypeB) {} };,c++,enums,C++,Enums,我觉得必须维护枚举的原因是Foos的所有者希望将他们创建的内容存储到数据库表中。如果系统重新启动,他们应该能够查看自己的表并说,“哦,是的,我有一个FooA需要初始化”,在这种情况下,只有将名为“FooType”的列设置为1,才能真正做到这一点 我只是想知道,这种给子类一个类型的方法是否是一种糟糕的设计,这种类型是枚举的一部分,他们必须知道。这似乎是多余的。这很好。通常,您希望避免“了解”多态层次结构中的类型-如果您对虚拟分派的性能满意,那么这应该是一个好的设计所需要的全部 但有时您确实需要一个

我觉得必须维护枚举的原因是
Foo
s的所有者希望将他们创建的内容存储到数据库表中。如果系统重新启动,他们应该能够查看自己的表并说,“哦,是的,我有一个
FooA
需要初始化”,在这种情况下,只有将名为“FooType”的列设置为1,才能真正做到这一点


我只是想知道,这种给子类一个类型的方法是否是一种糟糕的设计,这种类型是枚举的一部分,他们必须知道。这似乎是多余的。

这很好。通常,您希望避免“了解”多态层次结构中的类型-如果您对虚拟分派的性能满意,那么这应该是一个好的设计所需要的全部

但有时您确实需要一个强大的映射(例如,用于传递到某个外部资源),让一个枚举标识实例的实际“类型”可以节省一个字符串
dynamic\u cast
来完成相同的工作


您可以兼收并蓄,创建一个
virtual
函数,为类返回正确的枚举。但是坦率地说,您是在白白牺牲性能。

您可以使用多态性并对派生类使用重写流函数。 然后需要一个工厂函数来创建不同的派生对象,具体取决于从数据库中读取的内容

下面是一个小示例,其中数据库是一个
std::istringstream
,保存以前保存的内容

#include <iostream>
#include <memory>
#include <sstream>
#include <string>
#include <unordered_map>
#include <vector>

// An abstract base class for all entities you can store in the database
struct Foo {
    virtual ~Foo() = default;
    virtual void serialize(std::ostream&) const = 0; // must be overridden
    virtual void deserialize(std::istream&) = 0;     // must be overridden
};

// streaming proxies, calling the overridden serialize/deserialize member functions
std::ostream& operator<<(std::ostream& os, const Foo& f) {
    f.serialize(os);
    return os;
}

std::istream& operator>>(std::istream& is, Foo& f) {
    f.deserialize(is);
    return is;
}
//--------------------------------------------------------------------------------------
class FooA : public Foo {
public:
    void serialize(std::ostream& os) const override {
        // serializing by streaming its name and its properties
        os << "FooA\n" << a << ' ' << b << ' ' << c << '\n';
    }

    void deserialize(std::istream& is) override {
        // deserializing by reading its properties
        if(std::string line; std::getline(is, line)) {
            std::istringstream iss(line);
            if(not (iss >> a >> b >> c)) is.setstate(std::ios::failbit);
        }
    }

private:
    int a, b, c;
};

class FooB : public Foo {
public:
    void serialize(std::ostream& os) const override {
        os << "FooB\n" << str << '\n';
    }

    void deserialize(std::istream& is) override {
        std::getline(is, str);
    }

private:
    std::string str;
};
//--------------------------------------------------------------------------------------
// A factory function to create derived objects from a string by looking it up in a map
// and calling the mapped functor.
//--------------------------------------------------------------------------------------
std::unique_ptr<Foo> make_foo(const std::string& type) {
    static const std::unordered_map<std::string, std::unique_ptr<Foo>(*)()> fm = {
        {"FooA", []() -> std::unique_ptr<Foo> { return std::make_unique<FooA>(); }},
        {"FooB", []() -> std::unique_ptr<Foo> { return std::make_unique<FooB>(); }},
    };
    if(auto it = fm.find(type); it != fm.end()) return it->second(); // call the functor
    throw std::runtime_error(type + ": unknown type");    
}
//--------------------------------------------------------------------------------------
// Deserialize all Foos from a stream
//--------------------------------------------------------------------------------------
std::vector<std::unique_ptr<Foo>> read_foos(std::istream& is) {
    std::vector<std::unique_ptr<Foo>> entities;

    std::string type;
    while(std::getline(is, type)) {     // type is for example "FooA" here
        // Call make_foo(type), put the result in the vector and
        // stream directly to the added element (C++17 or later required)

        if(not (is >> *entities.emplace_back(make_foo(type)))) {
            throw std::runtime_error(type + ": deserializing failure");
        }
    }
    return entities;
}
//--------------------------------------------------------------------------------------
int main() {
    std::istringstream db(
        "FooA\n"
        "1 2 3\n"
        "FooB\n"
        "Hello world\n"
    );

    auto entities = read_foos(db);

    std::cout << "serialize what we got:\n";
    for(auto& fooptr : entities) {
        std::cout << *fooptr;
    }
}

我假设
FooA
FooB
有不同的成员变量?当您从数据库中读取数据时,您今天是如何处理这些数据的?是的,它们将有不同的成员和方法。但我明白你的意思。。如果它们是从数据库动态创建的,那么它将不能使用除基成员的方法之外的任何其他方法。。可能是多态性和不同派生类的不同流函数?您可以有一个工厂来创建对象,然后流式传输到它们?听起来可以通过使用
virtual std::string serialize()来修复它
虚拟空反序列化(std::string)将有效地将C++对象转换为/来自数据库表示。子类将重写此方法以提供自己的序列化机制。在这种情况下,为什么要使用
virtual
?基类只能有一个
getType()
函数?@Surt正好。。。另一种选择是在每个派生类中实现一个
virtual
,它只直接返回“正确”的枚举,但正如我所说的,与这个漂亮、干净、便宜的解决方案相比,这真是太过分了。
serialize what we got:
FooA
1 2 3
FooB
Hello world