C++ 如何在C+;中使子类返回一个不太通用的typedef+;?
免责声明:我理解以下可能不是正确的做事方式,并希望得到关于如何正确做事的建议 我有以下C++ 如何在C+;中使子类返回一个不太通用的typedef+;?,c++,oop,templates,inheritance,design-patterns,C++,Oop,Templates,Inheritance,Design Patterns,免责声明:我理解以下可能不是正确的做事方式,并希望得到关于如何正确做事的建议 我有以下typedef typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, VertexProperties, boost::no_property, GraphProperties> Witness; 我的意图是,Witness将是Solver.solve()的(抽象)返回类型。我想实现从Solver继承的类
typedef
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, VertexProperties, boost::no_property, GraphProperties> Witness;
我的意图是,Witness
将是Solver.solve()
的(抽象)返回类型。我想实现从Solver继承的类,并实现它们自己版本的函数solve()
。其中一个类将是SpecialSolver:public Solver
。这个SpecialSolver
应该返回比Witness
更专业的内容,比如说SpecialWitness
。因此,SpecialSolver
中的solve()
的实现应该如下所示
Witness SpecialSolver::solve(const Graph& graph)
{
SpecialWitness Special;
// Do some stuff
return Special;
}
我对C++中模板的认识不太好。我最初认为我可以这样做:
typedef boost::adjacency_list<boost::setS, boost::vecS, boost::directedS, SpecialVertexProperties, boost::no_property, SpecialGraphProperties> SpecialWitness;
typedef boost::邻接列表特殊性;
其中
specialvertexproperty:vertexproperty
和SpecialGraphProperties:graphproperty
。然后,SpecialWitness
将成为证人的一个子类型,我将获得我想要的结果。唉,这是不正确的,我想知道正确的设计应该是什么?我如何才能使特殊性
成为见证
的一种特殊形式,这样我就可以编写所有实现的客户端解算器
,对解算器界面来说很简单?这样不行,你会受到一种称为“对象切片”的效果的影响:
在返回对象时,使SpecialWitness
特殊的所有内容都被切断,只剩下基类Witness
部分
如果您想以多态方式返回,就无法绕过引用或指针;在函数中创建对象时,将选择指向动态分配对象的指针
现在,为了从一开始就防止内存泄漏,您应该使用智能指针(甚至不会显示原始指针变量…):
编辑:继承是什么样子的
class Witness
{
public:
virtual ~Witness() = default;
virtual void doSomething() { /* ... */ } // virtual allows to override
virtual void doSomethingElse() = 0; // pure virtual, no implementation
// in base class
// to allow the derived class to access the adjacency list, it might be more
// meaningful to make it protected (but that depends on your specific needs)
protected:
boost::adjacency_list<...> m_aList;
};
这样不行,你会受到一种叫做“对象切片”的效果的影响: 在返回对象时,使
SpecialWitness
特殊的所有内容都被切断,只剩下基类Witness
部分
如果您想以多态方式返回,就无法绕过引用或指针;在函数中创建对象时,将选择指向动态分配对象的指针
现在,为了从一开始就防止内存泄漏,您应该使用智能指针(甚至不会显示原始指针变量…):
编辑:继承是什么样子的
class Witness
{
public:
virtual ~Witness() = default;
virtual void doSomething() { /* ... */ } // virtual allows to override
virtual void doSomethingElse() = 0; // pure virtual, no implementation
// in base class
// to allow the derived class to access the adjacency list, it might be more
// meaningful to make it protected (but that depends on your specific needs)
protected:
boost::adjacency_list<...> m_aList;
};
我的意图是见证将是Solver.solve()的(抽象)返回类型
它不能是抽象返回类型,因为抽象类型不能实例化,因此不能返回
协变返回类型仅可用于间接寻址-指针或引用。当您打算在函数中创建对象时,这并不十分有效
此外,协方差要求从泛型类型继承专门类型
然后,特殊性将成为证人的一个子类型,我将达到我想要的结果。唉,这是不对的
为了澄清什么是不正确的:它将需要成为一个子类,但是boost::adjacenty_list
不会成为boost::adjacenty_list
的一个子类,所以它对于协变返回类型来说不是有效的类型
我想知道正确的设计应该是什么 这取决于你想要达到的目标 例如,如果运行时多态性不是必需的,那么您可以在整个过程中使用模板,让返回类型被模板化,并且不需要协方差 如果您确实需要运行时多态性,那么我认为一个合适的解决方案是始终使用相同的
graphproperty
type,并使用类型擦除技术允许子级创建的实例具有不同的行为
我的意图是见证将是Solver.solve()的(抽象)返回类型
它不能是抽象返回类型,因为抽象类型不能实例化,因此不能返回
协变返回类型仅可用于间接寻址-指针或引用。当您打算在函数中创建对象时,这并不十分有效
此外,协方差要求从泛型类型继承专门类型
然后,特殊性将成为证人的一个子类型,我将达到我想要的结果。唉,这是不对的
为了澄清什么是不正确的:它将需要成为一个子类,但是boost::adjacenty_list
不会成为boost::adjacenty_list
的一个子类,所以它对于协变返回类型来说不是有效的类型
我想知道正确的设计应该是什么 这取决于你想要达到的目标 例如,如果运行时多态性不是必需的,那么您可以在整个过程中使用模板,让返回类型被模板化,并且不需要协方差
如果您确实需要运行时多态性,那么我想一个合适的解决方案应该是始终使用相同的
graphproperty
类型,并使用类型擦除技术来允许孩子创建的实例具有不同的行为。semiofftopic:您的措辞有点奇怪,“返回一个typedef”没有太多意义Witness
只是一个别名,是一个不同的名称,但实际返回的类型仍然是boost::adjuncy_list
如果返回值,它必须具有完全相同的类型。我
class Witness
{
boost::adjacency_list<...> m_aList;
public:
virtual ~Witness() = default;
// provide some appropriate interface...
};
class Witness
{
public:
virtual ~Witness() = default;
virtual void doSomething() { /* ... */ } // virtual allows to override
virtual void doSomethingElse() = 0; // pure virtual, no implementation
// in base class
// to allow the derived class to access the adjacency list, it might be more
// meaningful to make it protected (but that depends on your specific needs)
protected:
boost::adjacency_list<...> m_aList;
};
class SpecialWitness : public Witness
{
public:
// you inherit already virtual destructor, so you don't need to specify
// explicitly...
void doSomething() override // you CAN override, if this is meaningful
{ /* ... */ }
void doSomethingElse() override // if you don't override, the class will
{ /* ... */ } // remain abstract (possible; if meaningful
// is up to you to decide...)
};