- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
在 C++ 中使用多态数据成员的最佳实践模式是什么?我所知道的最简单的方法就是使用普通指针。
例如,如果数据成员的类型不是多态的:
class Fruit {
public:
int GetWeight() { return 1; }
};
class Food {
public:
Food(Fruit f=Fruit()) : m_fruit(f) {}
void SetFruit(Fruit f) { m_fruit = f; }
Fruit GetFruit() { return m_fruit; }
int Test() { return m_fruit.GetWeight(); }
private:
Fruit m_fruit;
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
Fruit f;
food1.SetFruit(f);
}
int main() {
Fruit fruit1, fruit2;
Food food2(fruit1);
food2.SetFruit(fruit2);
food2.SetFruit(Fruit());
SomeFunction();
food1.Test();
food2.Test();
return 0;
}
可以很容易地以多种方式使用这些类,并将出错的可能性降到最低。
现在,如果我们将 Fruit 设为基类(使用多态),这是我能想到的最简单/最好的:
class Fruit {
public:
virtual int GetWeight() { return 0; }
};
class Apple : public Fruit {
public:
virtual int GetWeight() { return 2; }
};
class Banana : public Fruit {
public:
virtual int GetWeight() { return 3; }
};
class Food {
public:
Food(Fruit& f=defaultFruit) : m_fruit(&f) {}
void SetFruit(Fruit& f) { m_fruit = &f; }
Fruit& GetFruit() { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
static const Fruit m_defaultFruit = Fruit();
};
// Use the Food and Fruit classes
Food food1; //global scope
void SomeFunction() {
Apple a;
food1.SetFruit(a);
}
int main() {
Apple a;
Banana b;
Food food2(a);
food2.SetFruit(b);
food2.SetFruit(Apple()); //Invalid ?!
SomeFunction(); //Weakness: the food1.m_fruit points to invalid object now.
food1.Test(); //Can the compiler detect this error? Or, can we do something to assert m_fruit in Food::Test()?
food2.Test();
return 0;
}
有更好的方法吗?我尽量保持简单,不使用任何 new/delete 语句。 (注意:必须可以有默认值)
更新:让我们考虑一个更实际的例子:
class Personality {
public:
void Action();
};
class Extrovert : public Personality {
..implementation..
};
class Introvert : public Personality {
..implementation..
};
class Person {
...
void DoSomeAction() { personality->Action(); }
...
Personality* m_personality;
};
目标是拥有不同个性的人,并且通过子类化可以很容易地添加更多个性。实现这个的最佳方法是什么?从逻辑上讲,每种类型的个性我们只需要一个对象,因此 Person 复制或承担个性对象的所有权没有多大意义。是否有任何不同的方法/设计不需要我们处理复制/所有权问题?
最佳答案
在这种情况下,最好使用单独的默认构造函数和复制构造函数。此外,您不应该通过引用获取传递的地址;它可能是堆栈上的一个对象,很快就会消失。对于您的功能:
void SomeFunction() {
Apple a;
food1.SetFruit(a);
}
a
(因此 &a
)在函数返回时变为无效,因此 food1
将包含无效指针。
由于您正在存储一个指针,因此您应该期望 Food
取得传入的 Fruit
的所有权。
class Food {
public:
Food() : m_fruit(new Fruit()) {}
Food(Fruit* f) : m_fruit(f) {}
void SetFruit(Fruit* f) { if(m_fruit != f) { delete m_fruit; m_fruit = f; } }
Fruit& GetFruit() { return *m_fruit; }
const Fruit& GetFruit() const { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
};
另一个选项是让 Food
复制它传递的 Fruit
。这很棘手。在过去,我们会定义一个子类会覆盖的 Fruit::clone()
方法:
class Fruit {
public:
virtual int GetWeight() { return 0; }
virtual Fruit* clone() const { return new Fruit(*this); }
};
class Apple : public Fruit {
public:
virtual int GetWeight() { return 2; }
virtual Fruit* clone() const { return new Apple(*this); }
};
class Banana : public Fruit {
public:
virtual int GetWeight() { return 3; }
virtual Fruit* clone() const { return new Banana(*this); }
};
我不认为你可以用你需要的方式来制作一个虚拟构造函数来让它更漂亮。
然后 Food
类更改为:
class Food {
public:
Food() : m_fruit(new Fruit()) {}
Food(const Fruit& f) : m_fruit(f.clone()) {}
void SetFruit(const Fruit& f) { delete m_fruit; m_fruit = f.clone(); }
Fruit& GetFruit() { return *m_fruit; }
const Fruit& GetFruit() const { return *m_fruit; }
int Test() { return m_fruit->GetWeight(); }
private:
Fruit* m_fruit;
};
有了这个设置,您的 SomeFunction
就可以工作了,因为 food1
不再依赖于 a
的存在。
关于C++使用多态数据成员的最佳实践模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4161712/
我来自 Asp.Net 世界,试图理解 Angular State 的含义。 什么是 Angular 状态?它类似于Asp.Net中的ascx组件吗?是子页面吗?它类似于工作流程状态吗? 我听到很多人
我一直在寻找 3 态拨动开关,但运气不佳。 基本上我需要一个具有以下状态的开关: |开 |不适用 |关 | slider 默认从中间开始,一旦用户向左或向右滑动,就无法回到N/A(未回答)状态。 有人
我是一名优秀的程序员,十分优秀!