C ++中的多态子类型

时间:2014-02-02 00:13:55

标签: c++ inheritance polymorphism subtyping

我对C ++很陌生,我需要澄清从Java移植项目。

在Java中,我可以用这种方式声明一个基类及其派生的泛型:

public class GenericHost{
    public enum HostType{
        server,
        client
    }
    public HostType type_;
}

public class MyClient extends GenericHost{
    public String clientName;
}

public class MyServer extends GenericHost{
    public String serverName;
}



public abstract class GenericNetwork<hostType extends GenericHost> {
    public enum NetworkType{
        central,
        peripheral
    }
    private NetworkType type_;
    protected hostType masterHost;
    public hostType getMasterHost(){
        return masterHost;
    }
    public abstract String getName();
}

public class CentralNetwork extends GenericNetwork<MyServer>{
    @Override
    public String getName(){
        return masterHost.serverName;
    }
}

public class PeripheralNetwork extends GenericNetwork<MyClient>{
    @Override
    public String getName(){
        return masterHost.clientName;
    }
}

这允许我:

  1. 在派生类中,我可以使用指定派生类的方法和变量(例如serverName / clientName中的CentralNetwork / PeripheralNetwork而不是只有基类

  2. 派生类是tiped,所以编译器/编辑器可以建议我的每个方法&amp;代码编辑期间的变量

  3. 我被迫使用派生自基类(GenericNetwork / GenericHost)的类,每个错误都在编译时而不是运行时

    < / LI>
  4. 使用泛型的每个方法/变量都将在派生类中被视为子类而不是基类(例如在CentralNetwork中,getMasterHost将返回派生的{{1 }},而不是基础MyServer)。

  5. 我想知道C ++中是否存在类似内容。 我已经找到了模板,继承和子类型,但我找不到像在Java中那样更聪明的方法。我希望我错过了一些东西......

    编辑: 这是我在C ++中尝试过的:

    GenericHost

    我现在没有C项目,所以我在飞行中重写了它,对不起任何错误......

3 个答案:

答案 0 :(得分:0)

据我所知,没有明确的功能可以让你这样做。您可以使用static_cast,如果类型不兼容,这将给您一个编译时错误。

template <class hostType>
class GenericNetwork {
public:
    GenericNetwork() {
        static_cast<GenericHost*>((hostType*)nullptr); // or 0 or NULL if not C++11
    }
};

如果hostTypeGenericHost兼容,则演员会成功但不做任何事情。否则,您将收到编译时错误。

答案 1 :(得分:0)

没有专门的功能来明确约束模板参数(*),但你可以使用(C ++ 11)

static_assert( std::is_base_of<GenericHost, hostType>::value,
               "The template argument must be derived from GenericHost" );

(*)希望在C ++ 17中存在模板限制。

这是一个编译时断言,可以用作声明:

template<class hostType>
class GenericNetwork {
    static_assert( std::is_base_of<GenericHost, hostType>::value,
                   "The template argument must be derived from GenericHost" );

public:
    enum NetworkType{
        central,
        peripheral
    }

    virtual ~GenericNetwork(); // you typically want a virtual dtor in an ABC

    hostType& getMasterHost(){ // you might want to return a (const) reference
        return masterHost;
    }

    virtual std::string getName() = 0; // abstract

private:
    NetworkType type_;
    hostType masterHost;  // or protected

    // consider making the copy ctor and copy assignment op protected
    // to prevent unintended slicing
}

答案 2 :(得分:0)

正如大家所指出的,C ++模板可以实现这一点,因此它不值得专用语法。

这是一个相当字面的翻译,通过简单地执行它来强制执行基类要求。

#include <string>
struct GenericHost {
        enum HostType { server,client } type_;
};

template<class GenericHost=GenericHost>
struct MyClient : GenericHost     {  std::string clientName;  };    

template<class GenericHost=GenericHost>
struct MyServer : GenericHost     {  std::string serverName;  };


template< template<class> class SpecificHost, class GenericHost=GenericHost >
struct GenericNetwork
{
        typedef SpecificHost<GenericHost> hostType;
        virtual ~GenericNetwork() { };

        enum NetworkType { central, peripheral };

        hostType             getMasterHost() { return masterHost; }
        virtual std::string  getName() = 0;


protected: hostType     masterHost;
private:   NetworkType  type_;
};


struct CentralNetwork : GenericNetwork<MyServer> {
        std::string getName() { return masterHost.serverName; }
};

struct PeripheralNetwork : GenericNetwork<MyClient> {
        std::string getName() { return masterHost.clientName; }
};


// testing: force instantiation:
struct CentralNetwork makeme;
struct PeripheralNetwork metoo;
std::string doit() { return makeme.getName() + metoo.getName(); }

我相信这会得到所有四个需求,尽管错误会在不同的地方被发现。正如其他人指出static_cast<requiredBase*>((testedClass*)0);可以完成这项工作,但绕过保护需要工作,而不仅仅是一个错误,它会出现在类型系统中,所以我没有看到这一点。

(编辑:添加虚拟析构函数,今晚我没有甜点。坏狗。)