我已经了解了
type fields is an error-prone technique somewhere
我谷歌很多但没有令人满意的结果。虽然我分别知道type
和fields
的含义。我认为类型字段表示特定类型的字段,如
class marks;
class test {
marks number;
bool pass;
}
这里根据我的类型字段是数字和通过。
如果这是正确的,那么成分与它有何不同?
什么是type field
技术?怎么会出错?
请说出真正的意义。还举一个例子来说明它的邪恶本质以及它的替代品是什么?
答案 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;
}
请注意,上述代码不需要额外的enum
或switch
语句。调用Pet::ToString()
会自动为ToString()
s,Dog
等调用Cat
的正确实现,代码更少。我甚至不需要改变Pet
类;如果已经定义Turtle
,我可以根据需要放入Pet
课程。
对于可能合法使用的类型字段see this Stack Overflow question and the answers to that question。