1

I want to write a simple flexible ftp server in C++ that can be parametrized with a class to handle the user (check login and password, deliver files etc.) supplied on server initialization.

So I came up with this neat (so I thought) idea:

class FtpDelegate
{
public:
    FtpDelegate() {}
    virtual ~FtpDelegate() {}
    virtual bool login(QString username, QString password) = 0;
    // ...
};

class DummyDelegate : public FtpDelegate
{
public:
    virtual bool login(QString username, QString password)
    {
        return true;
    }
};

template<class Delegate>
class FtpServer : public QObject, Derived_from<Delegate, FtpDelegate>
{
    Q_OBJECT
public:
    explicit FtpServer(const QHostAddress &address = QHostAddress::Any,
                       quint16 port = 21,
                       QObject *parent = 0);

public slots:
    void newConnection();

private:
    QTcpServer *server;
    QHostAddress address;
};

template <class Delegate>
void FtpServer<Delegate>::newConnection()
{
    FtpDelegate *delegate = new Delegate();
    new FtpConnection (delegate, server->nextPendingConnection(), address, this);
}

class FtpConnection : public QObject
{
    Q_OBJECT
public:
    explicit FtpConnection(FtpDelegate *delegate,
                           QTcpSocket *socket,
                           const QHostAddress &address,
                           QObject *parent = 0);

public slots:
    void newDataConnection();

private:
    QTcpSocket *socket;
    QTcpServer *dataServer; // needed to transfer data to user
    QTcpSocket *dataSocket;
};


// server initialization
FtpServer<DummyDelegate> ftpServer();

and then (you probably saw that coming) bam!

Error: Template classes not supported by Q_OBJECT

it is likely that there are other errors or misconceptions too as I am only starting to learn the C++ template mechanism (and Qt as well).

My question is: what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class. Maybe there's some clever design pattern I just can't see. Eventually I can rewrite the network mechanism to boost if it is the best option.

mariusz
  • 645
  • 6
  • 10
  • 2
    Why do you want the `Delegate` to be part of `FtpServer`'s type? Why not just store a pointer to a `Delegate` in your `FtpServer`? – Tom Knapen Nov 05 '13 at 16:15
  • 1
    This is one of the situations where "normal" inheritance/polymorphism works perfectly well, don't pollute your code with tons of useless templates just because. – Matteo Italia Nov 05 '13 at 16:27
  • @TomKnapen I need to be able to create a new instance of Delegate for each new user connection (see implementation of FtpServer::newConnection()). – mariusz Nov 05 '13 at 23:13
  • @MatteoItalia I'm totally for simplicity but don't see a way to get rid of thos templates. Could you elaborate? Regarding inheritance - the only thing coming to my mind is merging FtpDelegate and FtpConnection but it doesn't solve the problem anyway. – mariusz Nov 05 '13 at 23:24

1 Answers1

2

It is not possible to create a template Q_OBJECT class (see this and answers).

Instead of using static inheritance, you should use a run-time inheritance, and inject an object inheriting from FtpDelegate class.


It looks like the FtpServer is actually a factory creating connections. From your question, I do not see why it has to be Q_OBJECT class. So you may need to reconsider your design, and simplify that class.


what is the best way to make it work without using ugly hacks like passing function pointers or needing to create a factory implementation for each concrete FtpDelegate's derived class.

The best way may be to have a factory class, which creates instances of FtpDelegate type. But you have so many problems in the posted code, that it is not possible to tell more without knowing all gory details.

Community
  • 1
  • 1
BЈовић
  • 62,405
  • 41
  • 173
  • 273
  • Actually the FtpServer does handle the main server and passes the socket associeted with a new connected peer (signaled with FtpServer::newConnection) to newly created FtpConnection instance. On the other hand, the FtpConnection creates a new server that manages data transfer (this is the ftp specification's requirement). Both classes inherit from QObject so they can use qt's signals and slots. I know I have to do some redesigning and that's why I'm asking for help :) – mariusz Nov 05 '13 at 23:46