派生的虚拟函数返回不同类型的指针



在我的程序中,我决定用一个名为Socket的类包装"sockets接口"(实际上只是我正在使用的部分)。我使用两个不同的"域":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*的地方,如果我传递sockaddr_ll*(并传递相应的socklen_t大小值),就不会有问题。

但在C++中,当尝试编译时,我会得到一个invalid covariant return type错误。我已经在这里、这里、这里读到了这个错误,我理解它的含义。无论如何,我找不到"变通"的方法。

我的问题是:既然我想返回指针(指针的大小相同),有没有办法强制编译器接受sockaddr_ll*作为sockaddr*?如果有办法的话,我该怎么做?

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

通常,如果您的公共API公开指针并鼓励类型转换,则需要重新设计。

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

您正在设计新的类型,您希望将其作为内置类型。这意味着将所有那些讨厌的指针隐藏在类内部。

例如,创建一个只引用抽象事物的顶级类,如果你想支持不同的底层API,那么就创建子类。。。但将这些API完全封装在抽象操作后面的子类中,如listen/accept/connect。

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()时,可能存在的下一组"美好事物"是什么。。。。然后做那些。

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

通过reinterpre_cast更改static_cast可能会达到您想要的效果。做这件事有多明智是另一回事。

首先,在虚拟函数中,您确实想要相同的返回类型。这是一种给定的情况,因为使用了虚拟函数,所以您可以拥有同一函数的不同版本,并根据对象类型使用正确的版本。因此,无论谁调用您的函数,都不知道将使用哪个版本的函数,因此,如果它们不同,也就不知道返回类型。

因此,无论哪种情况,都返回sockaddr。如果您发现您的调用者需要知道返回的实际类型,那么您可能不想从虚拟函数开始,或者您想要一个非虚拟的"getSpecificAddress"或类似的东西。

相关内容

  • 没有找到相关文章

最新更新