我有几个类似的类继承自相同的Base-Class / Interface(Base class 1),它们共享几个类似的函数,但是它们也有自己独特的函数。它们都有自己不同类的成员变量,每个变量都来自相同的Base-Class / Interface(Base class 2)。是否可以在基类1中定义基类2类型的变量,然后在使用基类1的类的实际实现中,使基类2类型的变量成为其正确的类型。有点难以解释,下面简单的例子。
//Base-Class 1
class Shape
{
public Shape() {}
ShapeExtra m_var;
//The common functions
public GetVar(){ return m_var; }
}
class Circle : Shape
{
public Circle() { m_var = new CircleExtra(); }
public void CircleFunc()
{
m_var.CircleExtraFunc();
}
}
class Triangle : Shape
{
public Triangle() { m_var = new TriangleExtra(); }
public void TriangleFunc()
{
m_var.TriangleExtraFunc();
}
}
.
.
.
//Base_Class 2
class ShapeExtra
{
public ShapeExtra() {}
}
class CircleExtra : ExtraClass
{
public CircleExtra() {}
void CircleExtraFunc() {//Do stuff}
}
class TriangleExtra : ExtraClass
{
public TriangleExtra() {}
void TriangleExtra() {//Do stuff}
}
.
.
.
因此,我需要将子类中的m_var
保留为其自己的唯一版本。因为现在(没有额外的CircleExtra m_var;
),GetVar()
有效,但在CircleFunc
中,m_var
仍然是ShapeExtra
的类型,因此< strong>不知道CircleExtraFunc
存在。我每次想要这样做时都可以施放m_var
,但这是重复的,在现实世界的情况下不值得。有没有办法在基于ShapeExtra
的唯一类中使用函数,同时将GetVar()
函数保留在Shape
?
如果我遗漏了任何内容,请提问。
答案 0 :(得分:1)
使用指针,这是完全可能的。 使用您的示例,您可以执行以下操作:
#include <iostream>
#include <memory>
using namespace std;
//Extras
class ShapeExtra
{
public:
ShapeExtra() {}
void ShapeFunc() { std::cout << "Shape"; }
virtual ~ShapeExtra() = default; //Important!
};
class Shape
{
public:
std::unique_ptr<ShapeExtra> m_var;
//require a pointer on construction
//make sure to document, that Shape class takes ownership and handles deletion
Shape(ShapeExtra* p):m_var(p){}
//The common functions
ShapeExtra& GetVar(){ return *m_var; }
void ShapeFunc() {m_var->ShapeFunc();}
};
class CircleExtra : public ShapeExtra
{
public:
void CircleExtraFunc() {std::cout << "Circle";}
};
class Circle : public Shape
{
CircleExtra* m_var;
public:
Circle() : Shape(new CircleExtra()) {
m_var = static_cast<CircleExtra*>(Shape::m_var.get());
}
void CircleFunc()
{
m_var->CircleExtraFunc();
}
};
int main() {
Circle c;
//use the ShapeExtra Object
c.GetVar().ShapeFunc();
//call via forwarded function
c.ShapeFunc();
//call the circleExtra Function
c.CircleFunc();
return 0;
}
注意使用指针和虚拟析构函数:
ShapeExtra
基类中使用虚拟析构函数,可以使用ShapeExtra*
来破坏任何派生类的对象。这很重要,因为std::unique_ptr<ShapeExtra>
而不是普通的C指针,我们确保在销毁Shape
时正确删除该对象。Shape
取得ShapeExtra*
的所有权。这尤其意味着,我们不会删除CirleExtra*
析构函数中的Circle
ShapeExtra*
构建,但也可以稍后使用std::unique_ptr::reset()
并在解除引用nullptr
时检查Shape::m_var
Circle
的构造函数时,我们首先创建一个新的CircleExtra
,然后传递给Shape
,最后执行Circle
的构造函数Circle
(最后创建的),然后Shape
也会为我们破坏ShapeExtra
,包括(通过虚函数)CircleExtra
答案 1 :(得分:1)
简单地使用继承而不使用指针是不可能的,因为C ++是一种静态和严格类型的语言。
您可以继承变量和函数,但是您需要转换函数返回值。
你也可以覆盖函数使其返回具体类型,但是你必须在函数内部转换变量。
您也可以在子类中使用具体类声明相同的var,但是您只需将变量隐藏在超类中并且不继承任何内容。
我宁愿选择使用模板的解决方案。使变量的类型为模板类型,并使用子类中的具体类型扩展模板。它会完美运作。
自从我上次使用C ++编程以来已经很长时间了,如果以下示例中存在错误,请原谅。我相信你可以很容易地让它发挥作用。
template <class S>
class Shape {
S m_var;
//......
public:
S var () {
return m_var;
}
//.......
}
class Circle: Shape <CircleExtra> {
// var method returns CircleExtra
//......
}
编辑: 关于一些注释,为了允许方法的虚拟调用,可以使用相关的返回类型。类似下面的例子。
class Shape {
public:
virtual ShapeExtra *var () = 0;
}
template <typename SE>
class ConcreteShape: Shape {
public:
virtual SE *var() {
return &m_var;
}
// Constructor, etc.
private:
SE m_var;
}
或者一些变化。现在,只要SE *与ShapeExtra *(类型参数扩展ShapeExtra)相关,具体形状就可以从扩展模板中受益。你可以通过Shape接口透明地调用方法。
答案 2 :(得分:1)
我建议采用以下方法:
class ShapeExtra
{
public:
virtual ~ShapeExtra() { }
virtual void SomeCommonShapeFunc() { std::cout << "Shape"; }
};
class Shape
{
public:
virtual ShapeExtra &GetVar() = 0; // Accessor function.
};
请注意,类Shape
根本没有任何数据成员。之后,您需要每个派生类:
class CircleExtra : public ShapeExtra
{
public:
void SomeCommonShapeFunc() { std::cout << "Circle"; }
};
class Circle : public Shape
{
CircleExtra m_var; // Data member with circle specific class.
public:
virtual ShapeExtra &GetVar() { return m_var; }
};
Circle
中虚拟方法的实现将返回对基类ShapeExtra
的引用。这将允许在基类中使用此额外内容。
请注意,根本不使用指针和模板。这简化了整体设计。