In a class without inheritance, I would expect the virtual
keyword to have no noticeable effect. However, in the following code example, adding it breaks compilation. I would like to understand the mechanism behind that. Why does the virtual
keyword break compilation?
#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;
};
See this question (closed for being too detailed) for more context if you would like to read about other aspects that I think are playing into this. Specifically templates and move constructors. The class template is required to reproduce this behavior.
The Error message is:
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 FilesMicrosoft Visual Studio2022CommunityVCToolsMSVC14.38.33130includexutility(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 FilesMicrosoft Visual Studio2022CommunityVCToolsMSVC14.38.33130includememory(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 FilesMicrosoft Visual Studio2022CommunityVCToolsMSVC14.38.33130includexutility(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 FilesMicrosoft Visual Studio2022CommunityVCToolsMSVC14.38.33130includememory(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 FilesMicrosoft Visual Studio2022CommunityVCToolsMSVC14.38.33130includememory(2094): note: see reference to function template instantiation 'void std::_Construct_in_place<_Ty,_Ty>(_Ty &,_Ty &&) noexcept(false)' being compiled
with
[
_Ty=Uncopyable
]