代码之家  ›  专栏  ›  技术社区  ›  Kjir

是否可以将成员初始化推迟到构造函数体?

  •  3
  • Kjir  · 技术社区  · 15 年前

    我有一个类,其中一个对象是没有默认构造函数的成员。我想在构造函数中初始化这个成员,但是在C++中我不能这样做。这是课程:

    #include <boost/asio.hpp>
    #include <boost/array.hpp>
    
    using boost::asio::ip::udp;
    
    template<class T>
    class udp_sock
    {
        public:
            udp_sock(std::string host, unsigned short port);
        private:
            boost::asio::io_service _io_service;
            udp::socket _sock;
            boost::array<T,256> _buf;
    };
    
    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost",
      unsigned short port = 50000)
    {
        udp::resolver res(_io_service);
        udp::resolver::query query(udp::v4(), host, "spec");
        udp::endpoint ep = *res.resolve(query);
        ep.port(port);
        _sock(_io_service, ep);
    }
    

    编译器基本上告诉我,它找不到UDP::套接字的默认构造函数,并且通过我的研究,我理解C++在调用构造函数之前隐式初始化每个成员。有什么方法可以做到这一点,或者是它太“面向Java”,在C++中是不可行的吗?

    我通过这样定义构造函数来解决这个问题:

    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost",
      unsigned short port = 50000) : _sock(_io_service)
    {
        udp::resolver res(_io_service);
        udp::resolver::query query(udp::v4(), host, "spec");
        udp::endpoint ep = *res.resolve(query);
        ep.port(port);
        _sock.bind(ep);
    }
    

    所以我的问题更多的是出于好奇,在C++中更好地理解OOP。

    7 回复  |  直到 15 年前
        1
  •  8
  •   Matthieu M.    15 年前

    定义构造函数时,有两种方法可以“初始化”属性:

    • 初始值设定项列表
    • 施工单位

    如果您没有明确地初始化初始值设定项列表中的一个属性,它仍然会为您初始化(通过调用其默认构造函数)。

    所以在本质上:

    class Example
    {
    public:
      Example();
    private:
      Bar mAttr;
    };
    
    // You write
    Example::Example() {}
    
    // The compiler understands
    Example::Example(): mAttr() {}
    

    当然,如果基础类型没有默认的构造函数,则此操作失败。

    有多种方法可以延迟此初始化。“标准”方法是使用指针:

    class Example { public: Example(); private: Bar* mAttr; };
    

    不过我更喜欢用 Boost.Optional 结合合适的附件:

    class Example
    {
    public: Example();
    private:
      Bar& accessAttr() { return *mAttr; }
      const Bar& getAttr() const { return *mAttr; }
      boost::Optional<Bar> mAttr;
    };
    
    Example::Example() { mAttr = Bar(42); }
    

    因为boost.optional意味着在分配上没有开销,在取消引用上也没有开销(对象是在适当的位置创建的),但是带有正确的语义。

        2
  •  1
  •   UncleBens    15 年前

    我认为这是一个可能的用例 boost::optional .

        3
  •  0
  •   Liz Albin    15 年前

    在C++中,最好在初始化器列表中初始化成员,而不是构造函数的主体,因此事实上,您可以考虑将其他成员放到初始化列表中。

    如果您正在考虑创建一个其他调用方所调用的构造函数,这将不适用于C++(参见 inheriting constructors )

        4
  •  0
  •   Artyom    15 年前

    我认为你的解决方案是正确的方法。

    您还可以通过使is指针(但它会更改代码和数据类型)来延迟对象的创建:

    std::auto_ptr<udp::socket> _sock;
    

    然后在身体里:

    _sock.reset(new udp::soket(_io_service, ep));
    

    但我认为你的“解决方法”比解决方法更正确。

        5
  •  0
  •   Rômulo Ceccon    15 年前

    你可以把 _sock 成员转换为 smart pointer :

    #include <boost/asio.hpp>
    #include <boost/array.hpp>
    #include <boost/scoped_ptr.hpp>
    
    using boost::asio::ip::udp;
    
    template<class T>
    class udp_sock
    {
        public:
            udp_sock(std::string host, unsigned short port);
        private:
            boost::asio::io_service _io_service;
            boost::scoped_ptr<udp::socket> _sock_ptr;
            boost::array<T,256> _buf;
    };
    
    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost",
      unsigned short port = 50000)
    {
        udp::resolver res(_io_service);
        udp::resolver::query query(udp::v4(), host, "spec");
        udp::endpoint ep = *res.resolve(query);
        ep.port(port);
        _sock_ptr.reset(new udp::socket(_io_service, ep));
    }
    
        6
  •  0
  •   Vite Falcon    15 年前

    如果要在类的构造函数中构造期间初始化变量,正确的方法是:

    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost", unsigned short port = 50000)
        :res(_io_service)
        ,query(udp::v4(), host, "spec")
        ,ep(*res.resolve(query))
        ,_sock(_io_service, ep)
    {
    }
    

    编辑:忘记提到“res”、“query”和“ep”应该是类的一部分。另一种粗略的方法(不使用插座作为指针)如下:

    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost", unsigned short port = 50000)
        :_sock(_io_service, udp::resolver(_io_service).resolve(udp::resolver::query(udp::v4(),host,"spec"))
    {
    }
    
        7
  •  0
  •   rkjnsn    13 年前

    在这种情况下,另一种选择是通过创建一个静态函数来构建ep来解决这个问题:

    #include <boost/asio.hpp>
    #include <boost/array.hpp>
    
    using boost::asio::ip::udp;
    
    template<class T>
    class udp_sock
    {
        public:
            udp_sock(std::string host, unsigned short port);
        private:
            static udp::endpoint build_ep(const std::string &host,
              unsigned short port, boost::asio::io_service &io_service);
    
            boost::asio::io_service _io_service;
            udp::socket _sock;
            boost::array<T,256> _buf;
    };
    
    template<class T>
    udp::endpoint udp_sock<T>::build_ep(const std::string &host,
      unsigned short port, boost::asio::io_service &io_service)
    {
        udp::resolver res(io_service);
        udp::resolver::query query(udp::v4(), host, "spec");
        udp::endpoint ep = *res.resolve(query);
        ep.port(port);
        return ep;
    }
    
    template<class T>
    udp_sock<T>::udp_sock(std::string host = "localhost",
      unsigned short port = 50000)
        : _sock(_io_service, build_ep(host, port, _io_service))
    {
    }