什么是类型字段

时间:2012-02-05 05:16:35

标签: c++

我已经了解了  type fields is an error-prone technique somewhere

谷歌很多但没有令人满意的结果。虽然我分别知道typefields的含义。我认为类型字段表示特定类型的字段,如

class marks;
class test {
marks number;
bool pass;
}

这里根据我的类型字段是数字和通过。 如果这是正确的,那么成分与它有何不同? 什么是type field技术?怎么会出错?

请说出真正的意义。还举一个例子来说明它的邪恶本质以及它的替代品是什么?

1 个答案:

答案 0 :(得分:9)

你几乎肯定会提到Bjarne Stroustrup在书The C++ Programming Language中讨论的类型字段。此上下文中的类型字段只是基类中某种类型的变量,表示其子类的实际类型。这是一个例子:

class Pet
{
public:
    enum PetType { Dog, Cat, Bird, Fish };

    void ToString()
    {
        switch(type)
        {
        case Pet::Dog: std::cout << "Dog" << std::endl; break;
        case Pet::Cat: std::cout << "Cat" << std::endl; break;
        case Pet::Bird: std::cout << "Bird" << std::endl; break;
        case Pet::Fish: std::cout << "Fish" << std::endl; break;
        }
    }

private:
    PetType type; // A type field.
};

class Dog : public Pet
{
public:
    Dog() { type = Dog; }
};

// And so on...

void Test(const Pet& p) { p.ToString(); }
int main()
{
    Dog d;
    Test(d);
    return 0;
}

这是实现ToString()方法的极其脆弱的方法。每次需要添加Pet的派生类时,都需要更新PetType枚举和ToString()方法。例如,如果我需要Turtle子类,我需要进行这些更改:

// ...
enum PetType { Dog, Cat, Bird, Fish, Tutle /* Added */};
void ToString(const Pet& p)
{
    switch(p.type)
    {
    case Pet::Dog: std::cout << "Dog" << std::endl; break;
    case Pet::Cat: std::cout << "Cat" << std::endl; break;
    case Pet::Bird: std::cout << "Bird" << std::endl; break;
    case Pet::Fish: std::cout << "Fish" << std::endl; break;
    case Pet::Turtle: std::cout << "Turtle" << std::endl; break; // Added
    }
}
// ...
class Turtle : public Pet
{
public:
    Turtle() { type = Turtle; } // Added
};

想象一下,Pet类是否具有比ToString()更多的功能;维护变成了一场噩梦。需要更改的代码很多,但重要的是,为了拥有Turtle类,我需要修改Pet类。这意味着需要更多测试,代码审查等。这显然违反了the open/closed principle。这就是类型字段极易出错的原因。

一种显着优越的方法是使用virtual函数:

class Pet
{
public:
    virtual void ToString() = 0;
};

class Dog : public Pet
{
public:
    virtual void ToString() { std::cout << "Dog" << std::endl; }
};

class Turtle : public Pet
{
public:
    virtual void ToString() { std::cout << "Turtle" << std::endl; }
};

// And so on...

void Test(const Pet& p) { p.ToString(); }
int main()
{
    Turtle t
    // Will call Turtle::ToString(), even though
    // Test() was only given a const Pet&
    Test(t); 
    return 0;
}

请注意,上述代码不需要额外的enumswitch语句。调用Pet::ToString()会自动为ToString() s,Dog等调用Cat的正确实现,代码更少。我甚至不需要改变Pet类;如果已经定义Turtle,我可以根据需要放入Pet课程。


对于可能合法使用的类型字段see this Stack Overflow question and the answers to that question