C++ 子类化和添加数据成员
我有一个类的层次结构,如下所示:C++ 子类化和添加数据成员,c++,class,C++,Class,我有一个类的层次结构,如下所示: class Critical { public: Critical(int a, int b) : m_a(a), m_b(b) { } virtual ~Critical() { } int GetA() { return m_a; } int GetB() { return m_b; } void SetA(int a) { m_a = a; }
class Critical
{
public:
Critical(int a, int b) : m_a(a), m_b(b) { }
virtual ~Critical() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
protected:
int m_a;
int m_b;
};
class CriticalFlavor : public Critical
{
public:
CriticalFlavor(int a, int b, int flavor) : Critical(a, b), m_flavor(flavor) { }
virtual ~CriticalFlavor() { }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
protected:
int m_flavor;
};
class CriticalTwist : public Critical
{
public:
CriticalTwist(int a, int b, int twist) : Critical(a, b), m_twist(twist) { }
virtual ~CriticalTwist() { }
int GetTwist() { return m_twist; }
void SetTwist(int twist) { m_twist = twist; }
protected:
int m_twist;
};
class Critical
{
public:
virtual int GetA() = 0;
virtual int GetB() = 0;
virtual void SetA(int a) = 0;
virtual void SetB(int b) = 0;
};
class CriticalImpl : public Critical
{
public:
CriticalImpl(int a, int b) : m_a(a), m_b(b) { }
~CriticalImpl() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
private:
int m_a;
int m_b;
};
class CriticalFlavor
{
public:
virtual int GetFlavor() = 0;
virtual void SetFlavor(int flavor) = 0;
};
class CriticalFlavorImpl : public Critical, public CriticalFlavor
{
public:
CriticalFlavorImpl(int a, int b, int flavor) : m_flavor(flavor), m_critical(new CriticalImpl(a, b)) { }
~CriticalFlavorImpl() { delete m_critical; }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
int GetA() { return m_critical->GetA(); }
int GetB() { return m_critical->GetB(); }
void SetA(int a) { m_critical->SetA(a); }
void SetB(int b) { m_critical->SetB(b); }
private:
int m_flavor;
CriticalImpl* m_critical;
};
从设计角度来看,上述内容对我来说并不合适,最让我困扰的是
添加成员变量似乎可以驱动这些类的接口
(执行上述操作的真正代码稍微复杂一些,但仍然采用相同的模式)。
当需要另一个“关键”类时,这种情况就会激增,而这个类只是添加了一些其他的属性
财产。
你觉得这样对吗?我如何重构这样的代码?
一个想法是只拥有一组接口,并在涉及基本对象时使用组合
例如:
class Critical
{
public:
Critical(int a, int b) : m_a(a), m_b(b) { }
virtual ~Critical() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
protected:
int m_a;
int m_b;
};
class CriticalFlavor : public Critical
{
public:
CriticalFlavor(int a, int b, int flavor) : Critical(a, b), m_flavor(flavor) { }
virtual ~CriticalFlavor() { }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
protected:
int m_flavor;
};
class CriticalTwist : public Critical
{
public:
CriticalTwist(int a, int b, int twist) : Critical(a, b), m_twist(twist) { }
virtual ~CriticalTwist() { }
int GetTwist() { return m_twist; }
void SetTwist(int twist) { m_twist = twist; }
protected:
int m_twist;
};
class Critical
{
public:
virtual int GetA() = 0;
virtual int GetB() = 0;
virtual void SetA(int a) = 0;
virtual void SetB(int b) = 0;
};
class CriticalImpl : public Critical
{
public:
CriticalImpl(int a, int b) : m_a(a), m_b(b) { }
~CriticalImpl() { }
int GetA() { return m_a; }
int GetB() { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
private:
int m_a;
int m_b;
};
class CriticalFlavor
{
public:
virtual int GetFlavor() = 0;
virtual void SetFlavor(int flavor) = 0;
};
class CriticalFlavorImpl : public Critical, public CriticalFlavor
{
public:
CriticalFlavorImpl(int a, int b, int flavor) : m_flavor(flavor), m_critical(new CriticalImpl(a, b)) { }
~CriticalFlavorImpl() { delete m_critical; }
int GetFlavor() { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
int GetA() { return m_critical->GetA(); }
int GetB() { return m_critical->GetB(); }
void SetA(int a) { m_critical->SetA(a); }
void SetB(int b) { m_critical->SetB(b); }
private:
int m_flavor;
CriticalImpl* m_critical;
};
在这里很难说继承是否是正确的想法,而不了解更多关于真实代码的信息。你想要多态性吗(如果是CriticalFlavor、CriticalTwist或CriticalWhatch,那么对一个临界点进行操作并获得不同的效果)?A和B的结构顺序和其他东西重要吗?您是否计划有一个更复杂的类树,包含CriticalFlavorTemperature和CriticalTwistColor之类的内容 也就是说,对于合成方法,我可能会这样做:
class Critical
{
public:
Critical(int a, int b) : m_a(a), m_b(b) { }
~Critical() { }
int GetA() const { return m_a; }
int GetB() const { return m_b; }
void SetA(int a) { m_a = a; }
void SetB(int b) { m_b = b; }
private:
int m_a;
int m_b;
};
class CriticalFlavor
{
public:
CriticalFlavor(int a, int b, int flavor) : m_flavor(flavor), m_critical(a, b) { }
~CriticalFlavor() {}
int GetFlavor() const { return m_flavor; }
void SetFlavor(int flavor) { m_flavor = flavor; }
int GetA() const { return m_critical.GetA(); }
int GetB() const { return m_critical.GetB(); }
void SetA(int a) { m_critical.SetA(a); }
void SetB(int b) { m_critical.GetB(b); }
private:
int m_flavor;
Critical m_critical;
};
@马吕斯从你的帖子中我所能理解的是,你想将数据访问与实际数据结构分开
class Critical
{
public:
virtual int GetA() = 0;
virtual int GetB() = 0;
virtual void SetA(int a) = 0;
virtual void SetB(int b) = 0;
};
class Flavor
{
public:
virtual int GetFlavor() = 0;
virtual void SetFlavor(int a) = 0;
};
template<class T>
class AccessCritical : public Critical
{
public:
AccessCritical(T &ref) : data(ref) {}
int GetA() { return (data.m_a); }
int GetB() { return (data.m_b); }
void SetA(int a) { data.m_a = a; }
void SetB(int b) { data.m_b = b; }
private:
T &data;
};
template<class T>
class AccessFlavor : public Flavor
{
public:
AccessFlavor(T &ref) : data(ref) {}
int GetFlavor() { return (data.m_flavor); }
void SetFlavor(int flavor) { data.m_flavor = flavor; }
private:
T &data;
};
struct MyStructA {
int m_a, m_b;
AccessCritical<MyStructA> critical;
MyStructA() : critical(*this) {}
};
struct MyStructB {
int m_flavor;
AccessFlavor<MyStructB> flavor;
MyStructB() : flavor(*this) {}
};
struct MyStructC {
int m_a, m_b;
int m_flavor;
AccessCritical<MyStructC> critical;
AccessFlavor<MyStructC> flavor;
MyStructC() : critical(*this), flavor(*this) {}
};
void processFlavor(Flavor *flavor)
{
flavor->SetFlavor(flavor->GetFlavor() * 3);
}
void processCritical(Critical *critical)
{
critical->SetA(critical->GetA() + critical->GetB());
}
int main() {
MyStructA a;
a.critical.SetA(2);
a.critical.SetB(3);
processCritical(& a.critical);
MyStructB b;
b.flavor.SetFlavor(4);
processFlavor(& b.flavor);
MyStructC c;
c.critical.SetA(20);
c.critical.SetB(30);
c.flavor.SetFlavor(40);
processFlavor(& c.flavor);
processCritical(& c.critical);
cerr << a.critical.GetA() << ' ' << a.critical.GetB() << endl;
cerr << b.flavor.GetFlavor() << endl;
cerr << c.critical.GetA() << ' ' << c.critical.GetB() << endl;
cerr << c.flavor.GetFlavor() << endl;
return 0;
}
类关键
{
公众:
虚拟int GetA()=0;
虚拟int GetB()=0;
虚空集a(int a)=0;
虚拟空位收缩(int b)=0;
};
风味
{
公众:
虚拟int GetFlavor()=0;
虚虚空SetFlavor(int a)=0;
};
模板
类访问关键:公共关键
{
公众:
AccessCritical(T&ref):数据(ref){}
int GetA(){return(data.m_a);}
int GetB(){return(data.m_b);}
void SetA(int a){data.m_a=a;}
void SetB(int b){data.m_b=b;}
私人:
T&data;
};
模板
类AccessFlavor:公共风味
{
公众:
AccessFlavor(T&ref):数据(ref){}
int GetFlavor(){return(data.m_flavor);}
void SetFlavor(int flavor){data.m_flavor=flavor;}
私人:
T&data;
};
结构MyStructA{
国际货币基金组织;
访问关键;
MyStructA():临界(*this){}
};
结构MyStructB{
int m_风味;
风味;
MyStructB():flavor(*this){}
};
结构MyStructC{
国际货币基金组织;
int m_风味;
访问关键;
风味;
MyStructC():critical(*this),flavor(*this){}
};
void processFlavor(Flavor*Flavor)
{
风味->设置风味(风味->获取风味()*3);
}
无效处理关键(关键*关键)
{
临界->SetA(临界->GetA()+临界->GetB());
}
int main(){
MyStructA a;
a、 关键毛(2);
a、 严重的挫折(3);
过程关键(a.critical);
MyStructB;
b、 香精(4);
工艺香精(b.flavor&b.flavor);
MyStructC;
c、 临界毛(20);
c、 严重。挫折(30);
c、 香精(40);
过程风味(c.flavor&c.flavor);
过程关键型(&c.critical);
cerr在我看来,这个层次结构的类只不过是数据桶,它们实际上除了充当某个底层数据模型的访问器之外,什么都不做。也许只是将您的设计限制为一个具有关键访问器的类,以及另一个更通用的命名属性方法(即std::string GetStringProperty)(std::string key){}?我的建议:找一位最有耐心、熟悉此代码的同事,并向他们提出以下问题。我假设由于IP问题,您没有发布更完整的示例。这使得很难提供好的建议
基于您的第一个代码示例,我会说只使用带有公共数据的结构,而不使用访问器。但是如果我看到了真正的代码,我可能会改变我的想法
对于您的第二个代码示例:一个好处是您可以让另一个类依赖于CriticalFlavor
,而不知道任何关于Critical
(例如,可以用于实现类似桥接模式的东西).但是,如果这种潜在的好处在您的情况下不是实际的好处,那么它只会使您的代码变得不必要的复杂和雅格尼(可能)
审阅者的评论:
基类应该是抽象的
我会说,“基类通常应该至少有一个虚方法,而不是析构函数”。如果没有,那么它只是在其他类之间共享公共代码或数据的一种手段;试着使用组合
大多数情况下,这些虚拟方法中至少有一个是纯虚拟的,因此基类是抽象的。但有时每个虚拟方法都有一个很好的默认实现,子类会选择要重写的方法。在这种情况下,请保护基类构造函数,以防基类构造函数实例化党卫军
基类中不建议使用受保护的成员
…而且它们在非基类中完全没有意义,所以这个建议基本上是说永远不要使用它们
什么时候建议使用受保护的成员变量?很少使用。您的代码示例不够现实,无法确定您要做什么或如何最好地编写。成员受到保护,但有公共getter/setter,因此它们基本上是公共的
按接口设计
不要被这件事冲昏头脑,否则你可能会为一个简单得惊人的任务而得到一个极其复杂的设计。在界面有意义的地方使用。如果没有看到一些“调用代码”,很难判断它们是否有意义使用Critical
及其子类的。谁调用GetFlavor
和GetTwist
调用代码是否仅通过Critical
接口与Critical
子类交互,或者调用代码是否知道特定子类和调用特定子类方法?您是否向Critical
添加了接口方法以提供对数据/函数的访问