наследование — Полиморфный подтип в переполнении стека

Я довольно новичок в 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. Производный класс имеет чаевые, поэтому компилятор / редактор может предложить мне каждый метод & переменная во время редактирования кода

  3. Я вынужден использовать класс, производный от базового класса (GenericNetwork / GenericHost), каждая ошибка происходит во время компиляции, а не во время выполнения

  4. Каждый метод / переменная, которые используют обобщенные значения, будут обрабатываться в производном классе как дочерний класс, а не как базовый класс (например, в CentralNetwork, getMasterHost вернет производное MyServerа не база GenericHost).

Я хотел бы знать, существует ли что-нибудь подобное в C ++.
Я уже искал шаблоны, наследование и подтипы, но я не могу найти способ сделать что-то умнее, как я делал в Java. Я надеюсь, что что-то пропустил …

РЕДАКТИРОВАТЬ:
Это то, что я пробовал в C ++:

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

class MyClient : public GenericHost{
public String clientName;
}

class MyServer : public GenericHost{
public String serverName;
}

template<class hostType : GenericHost>             <--WISH, forced base class
class GenericNetwork {
public enum NetworkType{
central,
peripheral
}
private NetworkType type_;
protected hostType masterHost;
public hostType getMasterHost(){
return masterHost;             <--WISH, should return MyServer / Myclient in derived class
}
public virtual std::string getName();
}

class CentralNetwork<MyServer> : public GenericNetwork{
public std::string getName(){
return masterHost.serverName;             <--WISH, tiped and suggested by editor / compiler
}
}

class PeripheralNetwork<MyClient>: public GenericNetwork{
public std::string getName(){
return masterHost.clientName;             <--WISH, tiped and suggested by editor / compiler
}
}

У меня сейчас нет проекта C, поэтому я переписал его на лету, извините за любую ошибку …

0

Решение

Насколько я знаю, нет явной функции, которая позволяет вам сделать это. Ты можешь использовать static_cast однако, это даст вам ошибку времени компиляции, если типы несовместимы.

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

Если hostType а также GenericHost совместимы, актерский состав будет успешным, но ничего не делать В противном случае вы получите ошибку времени компиляции.

0

Другие решения

Нет специальной функции для явного ограничения аргументов шаблона (*), но вы можете использовать (C ++ 11’s)

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

Я считаю, что это получает все четыре desiderata, хотя ошибки будут обнаружены в разных местах. Как указывают другие static_cast<requiredBase*>((testedClass*)0); может выполнить эту работу, но обход защиты требует работы, а не просто ошибки, и она будет отображаться в системе типов, поэтому я не вижу смысла.

(редактировать: добавить виртуальный деструктор, сегодня вечером для меня нет десерта. Плохая собака.)

0
По вопросам рекламы [email protected]