No Virtual constructors but virtual destructor
- There is no point in virtual constructor - you declare exactly what
type is created, and it is well known in compile time. The compiler
do not need [and actually cannot, since the dynamic dispatch is based
on information which is created only after the object was created].
So there are no virtual constructors. - Virtual destructors are important to prevent memory leaks, and
monitor the system. Assume you haveA* a = new B;
[B
inherits
fromA
], and you laterdelete a;
- the compiler has no way of
knowinga
is aB
[in the general case], and will invokeA
's
destructor - if it wasn't virtual, and you might get a memory leak,
or other faults. - Using virtual destructor - you ensure that
B
's destructor is
invoked, since aB
object is being destroyed.
In .NET can a class have virtual constructor?
no, a class cannot have a virtual constructor.
It doesn't make sense to have a virtual constructor. The order in which objects are constructed in C# is by constructing derived classes first, so the derived constructor is always called since the class you want to call is well known at the time of construction.
The other thing is, if you actually type this code out, you can quickly see that it makes very little sense at all
If you had:
public class BaseClass
{
public virtual BaseClass()
{
}
}
and then
public class InheritedClass : BaseClass
{
//overrides baseclass constructor but why would you do this given that the
//constructor is always going to be called anyway??
public override InheritedClass()
{
}
}
(Why) Is virtual base class constructor call required in pure virtual derived class?
Design issues (which clearly exist here) aside, I fully agree with your reasoning that, because Left
is an abstract class, no Left
constructor will ever have to call any Base
constructor and thus it is odd that it is required.
In fact, I tested your code with several compiler versions and it does compile just fine with gcc 7.1 and onwards, with clang 3.4.1 and onwards, and with all available msvc versions.
So, my assumption is, that this was just a bug in earlier compiler versions. Can anyone confirm this?
Also note, if you change virtual void leftsMethod() = 0;
to virtual void leftsMethod() {}
, so that Left
is not abstract anymore, the error returns, even with the latest versions. And this makes perfectly sense, as now you could instantiate a Left
instance and thus it would be up to Left
's constructor to call one of Base
's constructors.
Possible workaround
If you cannot switch to a newer compiler and if you cannot alter the implementation of Base
, this may be a working solution for you:
Define a dummy instance of CustomType
somewhere. Then, you can provide the "required" default constructors like this:
class CustomType{};
class Base
{
public:
Base( CustomType& obj ) : refObj_( obj ) {}
private:
CustomType& refObj_;
};
static CustomType dummy;
class Left : public virtual Base
{
protected:
Left() : Base(dummy) {}; // note here
public:
virtual void leftsMethod() = 0;
};
class Right : public virtual Base
{
protected:
Right() : Base(dummy) {}; // and here
public:
virtual void rightsMethod() = 0;
};
class Bottom : public Left, public Right
{
public:
Bottom( CustomType& obj ) : Base( obj ), Left(), Right() {}
virtual void leftsMethod() override {}
virtual void rightsMethod() override {}
};
void test()
{
CustomType c;
Bottom b(c);
}
This is just to make the compiler happy, your argument that these constructors will never call Base(dummy)
still holds.
Note however, that Base
should really have a virtual destructor! I don't know if you just didn't include it here for brevity or if it really doesn't have one. If it doesn't, it's a very bad idea to build a class hierarchy on top of it.
Constructors and destructor must be virtual?
You cannot have Virtual constructor in C++ why no virtual Constructor.
Virtual destructors are useful when you can delete an instance of a derived class through a pointer to base class. Refer to When to use Virtual Destructor.
Is using a C++ Virtual Constructor generally considered good practice?
All the author has done is implement prototyping and cloning. Both of which are powerful tools in the arsenal of patterns.
You can actually do something a lot closer to "virtual constructors" through the use of the handle/body idiom:
struct object
{
void f();
// other NVI functions...
object(...?);
object(object const&)
object& operator = (object const&);
~object();
private:
struct impl;
impl * pimpl;
};
struct object::impl
{
virtual void f() = 0;
virtual impl* clone() = 0;
// etc...
};
struct impA : object::impl { ... };
struct impB : object::impl { ... };
object::object(...?) : pimpl(select_impl(...?)) {}
object::object(object const& other) : pimpl(other.pimpl->clone()) {}
// etc...
Don't know if anyone has declared this an Idiom but I've found it useful and I'm sure others have come across the same idea themselves.
Edit:
You use factory methods or classes when you need to request an implementation for an interface and do not want do couple your call sites to the inheritance tree behind your abstraction.
You use prototyping (clone()) to provide generic copying of an abstraction so that you do not have to determine type in order to make that copy.
You would use something like I just showed for a few different reasons:
1) You wish to totally encapsulate the inheritance relation behind an abstraction. This is one method of doing so.
2) You want to treat it as a value type at the abstract level (you'd be forced to use pointers or something otherwise)
3) You initially had one implementation and want to add new specifications without having to change client code, which is all using the original name either in an auto declaration or heap allocation by name.
Related Topics
Standard Library Sort and User Defined Types
What Is More Efficient? Using Pow to Square or Just Multiply It With Itself
Linux: Executing Child Process With Piped Stdin/Stdout
Default Value of Function Parameter
Template Specialization of Particular Members
Arrays VS Vectors: Introductory Similarities and Differences
Difference Between Erase and Remove
C++ How to Determine Whether a Pointer Points to a Valid Object
C++: What Regex Library Should I Use
How to Implement Make_Unique Function in C++11
When Passing an Array to a Function in C++, Why Won't Sizeof() Work the Same as in the Main Function
How to Compile For Os X in Linux or Windows
C/C++ Unsigned Integer Overflow
C++11 Allows In-Class Initialization of Non-Static and Non-Const Members. What Changed
When Should I Use _Mm_Sfence _Mm_Lfence and _Mm_Mfence
What Is the Logic Behind the "Using" Keyword in C++