代码之家  ›  专栏  ›  技术社区  ›  Martin Ba

当对虚拟基类使用boost序列化时,C4250(类通过支配权继承成员)的原因是什么?

  •  1
  • Martin Ba  · 技术社区  · 14 年前

    这个 意思 关于VC++编译警告 C4250 'class1' : inherits 'class2::member' via dominance 我很清楚。(但请参见 here

    我目前有一个问题,在序列化类层次结构时收到此警告 有抽象基类的

    请注意 我的课程 不要 boost::detail::is_virtual_base_of_impl<...> 序列化派生类的实例时。(似乎在使用 is_virtual_base_of 来自Boost.TypeTraits。)


    下面是在Visual Studio 2005上复制警告的最小代码示例。请注意,代码应按原样删除到一个cpp文件中,并应进行编译。

    BOOST_CLASS_EXPORT 不使用则警告不触发,但更有趣的是警告也 如果派生类触发 使用 virtual 继承权!(所以也许我根本不懂C4250。)

    // -- std includes --
    #include <iostream>
    #include <sstream>
    #include <string>
    
    // -- boost serialization --
    #define BOOST_SERIALIZATION_DYN_LINK
    #include <boost/archive/text_oarchive.hpp>
    #include <boost/archive/text_iarchive.hpp>
    #include <boost/serialization/export.hpp>
    
    // Base with serialization support
    struct Base
    {
      virtual ~Base() {};
      virtual void DoStuff() const {
        std::cout << "Base@[" << static_cast<const void*>(this) << "]::DoStuff() called\n";
      }
    
      template<class Archive> // serialization support!
      void serialize(Archive & ar, const unsigned int file_version)  { /*empty*/  }
    };
    
    // (The only) Specific class with ser. support
    struct Concrete2 : virtual/*!C4250!*/ public Base
    {
      virtual void DoStuff() const {
        std::cout << "Concrete2@[" << static_cast<const void*>(this) << "]::DoStuff() called\n";
      }
    
      template<class Archive> // serialization support!
      void serialize(Archive & ar, const unsigned int ver) {
        ar & boost::serialization::base_object<Base>(*this);
        // This is just a test - no members neccessary
        std::cout << "Concrete2::serialize!" << typeid(ar).name() << "\n";
      }
    };
    // Without guid export -> *no* C4250, even *with* virtual inheritance
    // (however, can't be serialized via base class pointer anymore)
    BOOST_CLASS_EXPORT(Concrete2); 
    
    BOOST_CLASS_TRACKING(Concrete2, boost::serialization::track_never);
    
    int main() {
      using namespace std;
      Concrete2 obj1;
      obj1.DoStuff();
    
      // The following test code is not neccessary to generate the warning ...
      // (but is neccessary to show if base-pointer serialization works at runtime)
      Base* ref1 = &obj1;
      ostringstream out_buf;
      boost::archive::text_oarchive out_archive(out_buf);
      out_archive << ref1;
      const string buf = out_buf.str();
    
      cout << "Serialized obj:\n~~~~\n";
      cout << buf;
      cout << "\n~~~~~\n";
    
      std::istringstream in_buf(buf);
      boost::archive::text_iarchive in_archive(in_buf);
      // Concrete2 obj2;
      Base* ref2;
      in_archive >> ref2;
      if(ref2)
        ref2->DoStuff();
      delete ref2;
    }
    

    下面是编译器警告(啊!):

    1>...\boost_library-1_44_0\boost\type_traits\is_virtual_base_of.hpp(61) : warning C4250: 'boost::detail::is_virtual_base_of_impl<Base,Derived,tag>::X' : inherits 'Concrete2::Concrete2::DoStuff' via dominance
    1>        with
    1>        [
    1>            Base=type,
    1>            Derived=Concrete2,
    1>            tag=boost::mpl::bool_<true>
    1>        ]
    1>        ...\boostserializewarningtest\vbc.cpp(27) : see declaration of 'Concrete2::DoStuff'
    ...
    1>        ...\boost_library-1_44_0\boost\mpl\eval_if.hpp(40) : see reference to class template instantiation 'boost::mpl::if_<T1,T2,T3>' being compiled
    1>        with
    1>        [
    1>            T1=boost::is_virtual_base_of<type,Concrete2>,
    1>            T2=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_virtual_base<Concrete2,type>>,
    1>            T3=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_primitive<Concrete2,type>>
    1>        ]
    1>        ...\boost_library-1_44_0\boost\serialization\void_cast.hpp(279) : see reference to class template instantiation 'boost::mpl::eval_if<C,F1,F2>' being compiled
    1>        with
    1>        [
    1>            C=boost::is_virtual_base_of<type,Concrete2>,
    1>            F1=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_virtual_base<Concrete2,type>>,
    1>            F2=boost::mpl::identity<boost::serialization::void_cast_detail::void_caster_primitive<Concrete2,type>>
    1>        ]
    1>        ...\boost_library-1_44_0\boost\serialization\base_object.hpp(68) : see reference to function template instantiation 'const boost::serialization::void_cast_detail::void_caster &boost::serialization::void_cast_register<Derived,Base>(const Derived *,const Base *)' being compiled
    1>        with
    1>        [
    1>            Derived=Concrete2,
    1>            Base=type
    1>        ]
    ...    
    1>        ...\boost_library-1_44_0\boost\serialization\export.hpp(128) : while compiling class template member function 'void boost::archive::detail::`anonymous-namespace'::guid_initializer<T>::export_guid(boost::mpl::false_) const'
    1>        with
    1>        [
    1>            T=Concrete2
    1>        ]
    1>        ...\boostserializewarningtest\vbc.cpp(40) : see reference to class template instantiation 'boost::archive::detail::`anonymous-namespace'::guid_initializer<T>' being compiled
    1>        with
    1>        [
    1>            T=Concrete2
    1>        ]
    

    1 回复  |  直到 8 年前
        1
  •  0
  •   Martin Ba    14 年前

    原因其实是 is_virtual_base_of

    ...
    struct base { 
        virtual void mf() { };
    };
    struct derived_normal : public base { 
        virtual void mf() { };
    };
    struct derived_virt : virtual public base { 
        virtual void mf() { };
    };
    
    int main() {
        using namespace std;
    
        cout << "boost::is_virtual_base_of<base, derived_normal>::value reports: ";
        // The following line DOES NOT cause C4250
        cout << boost::is_virtual_base_of<base, derived_normal>::value << endl;
    
        cout << "boost::is_virtual_base_of<base, derived_virt> reports: ";
        // The following line causes C4250:
        cout << boost::is_virtual_base_of<base, derived_virt>::value << endl;
     ...
    

    FWIW,这种类型特征工具在boost序列化中的用法如下:

    • BOOST_EXPORT_CLASS
      • BOOST_CLASS_EXPORT_IMPLEMENT ->
        • struct guid_initializer (在export.hpp中)—>
        • void_cast_register ->此处是否使用虚拟库

    #pragma warning( push )
    #pragma warning( disable : 4250 ) // C4250 - 'class1' : inherits 'class2::member' via dominance
    #include ...
    #pragma warning( pop ) // C4250