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...) 
};