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

虚拟关键字是如何破坏编译的?

  •  4
  • lucidbrot  · 技术社区  · 7 月前

    在没有继承的类中,我希望 virtual 关键字没有明显的效果。但是,在下面的代码示例中,添加它会中断编译。我想了解这背后的机制。为什么 虚拟 关键字中断编译?

    它在没有虚拟关键字的情况下编译良好。

    #define USE_VIRTUAL 1
    // compile with: cl /W4 /EHsc main.cpp /link /out:main.exe
    #include<iostream>
    #include<memory>
    
    struct Dummy {int i = 3;};
    class Uncopyable {
        public:
            // Implicitly delete the copy constructor by having
            // a non-copyable member.
            std::unique_ptr<Dummy> m_innerPtr;
    
            // A virtual destructor to allow correct inheritance.
            // I first thought that this implicitly deletes the 
            // copy-assignment and copy-constructor, 
            // but it does not. It does, however, implicitly
            // delete the move constructor and assignment.
            virtual ~Uncopyable() = default;
    
            // accessible constructor
            Uncopyable() = default;
            Uncopyable(std::unique_ptr<Dummy> dummy):m_innerPtr(std::move(dummy)){};
    
    };
    
    
    template <typename MaybeCopyable>
    class Bamboozle {
        public: 
        void foo(std::shared_ptr<MaybeCopyable> obj) {
            std::cout << "Reached Bamboozle::foo(shared_ptr)" << std::endl;
        }
    
        // overload that takes an object by value
    #if USE_VIRTUAL
        virtual
    #endif
        void foo(MaybeCopyable obj){
            std::cout << "Reached Bamboozle::foo(Uncopyable)" << std::endl;
            foo(std::make_shared<Uncopyable>(std::move(obj)));
        }
    };
    
    
    
    int main(int argc, char** argv){
        // construct param objects
        std::shared_ptr<Uncopyable> uncSharedPtr = std::make_shared<Uncopyable>();
    
        // prints Bamboozle::foo(shared_ptr)
        Bamboozle<Uncopyable> bamboozleObj;
        bamboozleObj.foo(uncSharedPtr);
        return 0;
    };
    
    

    看见 this question (closed for being too detailed) 如果你想阅读我认为正在发挥作用的其他方面,请参阅更多上下文。特别是模板和移动构造函数。类模板是再现此行为所必需的。

    错误消息为:

    cl /W4 /EHsc main.cpp /link /out:main.exe
    Microsoft (R) C/C++ Optimizing Compiler Version 19.38.33134 for x64
    Copyright (C) Microsoft Corporation.  All rights reserved.
    
    main.cpp
    main.cpp(46): warning C4100: 'argv': unreferenced formal parameter
    main.cpp(46): warning C4100: 'argc': unreferenced formal parameter
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xutility(255): error C2280: 'Uncopyable::Uncopyable(const Uncopyable &)': attempting to reference a deleted function
    main.cpp(24): note: compiler has generated 'Uncopyable::Uncopyable' here
    main.cpp(24): note: 'Uncopyable::Uncopyable(const Uncopyable &)': function was implicitly deleted because a data member invokes a deleted or inaccessible function 'std::unique_ptr<Dummy,std::default_delete<Dummy>>::unique_ptr(const std::unique_ptr<Dummy,std::default_delete<Dummy>> &)'
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\memory(3319): note: 'std::unique_ptr<Dummy,std::default_delete<Dummy>>::unique_ptr(const std::unique_ptr<Dummy,std::default_delete<Dummy>> &)': function was explicitly deleted
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\xutility(255): note: the template instantiation context (the oldest one first) is
    main.cpp(51): note: see reference to class template instantiation 'Bamboozle<Uncopyable>' being compiled
    main.cpp(38): note: while compiling class template member function 'void Bamboozle<Uncopyable>::foo(MaybeCopyable)'
            with
            [
                MaybeCopyable=Uncopyable
            ]
    main.cpp(40): note: see reference to function template instantiation 'std::shared_ptr<Uncopyable> std::make_shared<Uncopyable,Uncopyable>(Uncopyable &&)' being compiled
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\memory(2769): note: see reference to function template instantiation 'std::_Ref_count_obj2<_Ty>::_Ref_count_obj2<_Ty>(_Ty &&)' being compiled
            with
            [
                _Ty=Uncopyable
            ]
    C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.38.33130\include\memory(2094): note: see reference to function template instantiation 'void std::_Construct_in_place<_Ty,_Ty>(_Ty &,_Ty &&) noexcept(false)' being compiled
            with
            [
                _Ty=Uncopyable
            ]
    
    1 回复  |  直到 7 月前
        1
  •  10
  •   HolyBlackCat    7 月前

    添加析构函数时,将以静默方式删除move构造函数和move赋值。它也应该删除复制构造函数和复制赋值,但目前没有(这是不推荐的),所以移动这样的类会自动复制它。

    您的类没有可回退的复制操作,因此当它失去移动操作时,它将变得不可移动。

    添加此:

    Uncopyable(Uncopyable &&) = default;
    Uncopyable &operator=(Uncopyable &&) = default;
    

    至于为什么添加 virtual 破坏事物。 虚拟 强制无条件实例化函数,而非虚拟函数只有在使用时才被实例化,并且不能调用有问题的函数。