0

在我的程序中,我决定用一个名为 Socket 的类来包装“套接字接口”(实际上只是我正在使用的部分)。我正在使用两个不同的“域”:AF_PACKET 和 AF_INET。因为这些域具有不同的地址结构,所以我决定也包装它们的地址。

我做了一个像下面这样的小班:

class SockAddress
{
    public:
    SockAddress();

    virtual sockaddr* getAddress();
    virtual socklen_t getAddrLen();

    private:

    sockaddr address_;
};

基于这个类,我创建了另一个类,而不是返回一个sockaddr*返回的 sockaddr_ll*`

virtual sockaddr_ll* getAddress();
...
sockaddr_ll address_;

在 C 中,它们都是指针。我只知道在任何地方sockaddr*都需要 a ,如果我通过 a sockaddr_ll*(并传递相应的socklen_t大小值)就不会有问题。

但是在 C++ 中,尝试编译时,我得到一个invalid covariant return type错误。我已经在此处此处此处阅读了有关此错误的信息,并且我了解它的含义。无论如何,我找不到“解决方法”这个问题的方法。

我的问题是:由于我想返回指针(并且指针将具有相同的大小),有没有办法强制编译器接受sockaddr_ll*as a sockaddr*?而且,如果有办法,我该怎么做?

(如果没有办法,解决这个问题的“正确方法”可能是什么?)

4

3 回答 3

2

一般来说,如果你的公共 API 暴露了指针并鼓励类型转换,你需要重新设计。

当你在一个类中包装一些东西时,重点是隐藏细节,而不仅仅是为它们制作一个类似结构的持有者。

您正在设计新的类型,您希望它们就像是内置的一样。这意味着将所有这些讨厌的指针隐藏在类中。

例如,创建一个仅引用抽象事物的顶级类,然后如果您想支持不同的低级 API 则子类......但将这些 API 完全封装在抽象操作后面的子类中,如监听/接受/连接。

class Socket
{
   public:
      Socket(IPAddress address, int port);
      virtual ~Socket() = 0; // close/clean up resources
      virtual void connect() = 0;
      ...
};  

然后子类化 Socket 类来封装底层 API 的细节。

另一种选择是反转事物,以便 SockAddress 具有隐藏的操作并采用抽象套接字进行处理:

class SockAddress
{
      void doSomethingForSocket(Socket *s) { ... }
}

我通常会告诉人们首先编写使用 API 的程序,并假设你有一个摇滚明星 API 可以为你做很酷的事情:

Socket s("192.168.5.100", 80);
s.connect();
int i;
i << s;
...
ServerSocket server("*", 80);
Socket *client;
while((client = server.accept()) != null) {
   ...
}

然后着手制作那个API。在构建 API 本身时使用相同的技术。在编写 connect() 时,可能存在的下一组“好东西”会是非常好的......然后制作它们。

于 2012-09-05T18:26:44.273 回答
0

在 C 中,它们都是指针。我只知道在任何地方都需要 sockaddr*,如果我通过 sockaddr_ll*

我想要一个确认的参考。我很确定它违反了 C 的别名规则。

当我使用的编译器不可用时,我已经实现了这样的协变返回。

class SockAddress
{
public:
    SockAddress();

    sockaddr* getAddress() { return doGetAddress(); }

protected:
    virtual sockaddr* doGetAddress() { return ...; } 
};

class SockAddress_ll: public SockAddress
{
public:
    SockAddress();
    sockaddr_ll* getAddress() { return static_cast<sockaddr_ll*>(doGetAddress()); }

protected:
    sockaddr* doGetAddress() { return ...; }
};

通过 reinterpret_cast 更改 static_cast 可能会做你想要的。这样做有多明智是另一回事。

于 2012-09-05T18:23:39.140 回答
0

首先,在虚函数中,您确实需要相同的返回类型。这是给定的,因为使用了虚函数,因此您可以拥有同一函数的不同版本,并根据对象类型使用正确的版本。因此,调用您的函数的人不知道将使用哪个版本的函数,因此如果它们不同,则无法知道返回类型。

因此,在任何一种情况下都返回 sockaddr。如果你发现你的调用者需要知道返回的实际类型,你可能不想使用虚函数开始,或者你想要一个非虚的“getSpecificAddress”或类似的东西。

于 2012-09-05T18:24:26.223 回答