This is purely a theoretical question. I don't have a particular use case in mind.
Can the virtuality of a C++ function be suppressed somewhere down the class hierarchy, or is it that once a virtual function is defined in a base class, it remains virtual down the rest of its class hierarchy?
I wrote some sample code where I was attempting to suppress the virtuality of a method defined up the class hierarchy but I did not succeed. My sample code follows:
class Base {
public:
virtual void myFunc() {
std::cout << "myFunc in Base" << std::endl;
}
};
class Child : public Base {
public:
void myFunc() {
std::cout << "myFunc in Child" << std::endl;
}
};
class GrandChild : public Child {
public:
void myFunc() {
std::cout << "myFunc in GrandChild" << std::endl;
}
};
int main() {
Base* ptr = new GrandChild();
ptr->myFunc();
return 0;
}
The output is as follows:
myFunc in GrandChild
One thing you can do is create a member with a different signature (even using defaulted arguments).
That is:
struct Base
{
virtual void foo()
{
std::cout << "Base::foo" << std::endl;
}
};
struct Derived : Base
{
void foo(int = 0)
{
std::cout << "Derived::foo" << std::endl;
}
};
...
Base * ptr = new Derived;
ptr->foo(); // will invoke Base::foo()
#include <iostream>
#include <memory>
using namespace std;
class Base
{
public:
virtual void foo() = 0;
protected:
int num{ 1 };
public:
Base() {
cout << "Base class constructor" << endl;
}
virtual ~Base()
{
cout << "Base class destructor " << endl;
}
private:
};
class Derive : public Base {
public:
Derive() {
cout << "Derive class constructor" << endl;
}
~Derive() {
cout << "Derive class destructor " << endl;
}
public:
void foo() override{
cout << "Derive class Foo function" << endl;
}
};
int main() {
unique_ptr<Base> b = make_unique<Base>(new Derive());
b->foo();
}
I get below error when I build this code.
in instantiation of function template specialization 'std::make_unique<Base, Derive *>' requested here unique_ptr b = make_unique(new Derive());
unimplemented pure virtual method 'foo' in 'Base' virtual void foo() = 0;
Does anyone know what is the reason of this error?
Note: I tried on https://godbolt.org/ and selected clang 11
In your main() function, do this instead:
unique_ptr<Base> b(new Derive());
This is because std::make_unique() takes the actual constructor arguments. You can't do that with polymorphism, but there's nothing wrong with directly instanstiating a std::unique_ptr directly with a heap allocated resource.
Do prefer std::make_unique() where it makes sense, though. This just isn't one of those cases.
Imagine these classes:
class Base {
public:
Base() : Base(false)
{ }
virtual ~Base() = default;
void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
protected:
Base(bool skip_init)
{
cout << "Base::Base" << endl;
if (!skip_init) init();
}
};
class Derived : public Base {
public:
Derived() : Base(true)
{
cout << "Derived::Derived" << endl;
init();
}
virtual ~Derived() = default;
void init()
{
cout << "Derived::init" << endl;
Base::init();
// ...
}
virtual void check() override
{
cout << "Derived::check" << endl;
Base::check();
// ...
}
};
Then constructing a Derived instance would result in
Base::Base
Derived::Derived
Derived::init
Base::init
Derived::check
Base::check
which is exactly what I want to achieve.
It satisfies these requirements:
Base defines init() with operations common to all subclasses and should be used right after construction of whole object (and only there)
init() can contain virtual functions inside, but since it should be called only in the final constructor, it should not cause any harm
check() can be called any time, not only from init() (it should be independent from it), and should always perform all checking, not only those related to the subclass
My best approach so far, as above, was to use protected constructor with flag that avoids calling "incomplete" Base::init() because of virtual functions do not work in superclass constructor. (Without the flag, Base::check() would be called twice.)
My question is: isn't there a better, preferably somehow standard technique, that deals with calling virtual routines after whole object is initialized (pardon for vague terminology)? And of course without requiring users to call init() explicitly (it should stay protected).
One possible use case (mine): Base stands for e.g. an array of general mathematical formulas which must satisfy several constraints. Derived (i.a.) restricts these constraints, add some, can override some particular checks, but mostly still use these from Base. E.g. Base::check_formulas() applies check_formula(f) to every f, and Derived needs to override only check_formula function.
EDIT:
As it is better to avoid virtual functions inside constructors at all, it appears not to be possible to achieve virtual function call from within the object itself, so the object must be constructed "externally" before calling these functions.
Both #StoryTeller and #Caleth suggests deal with this issue, either via dynamic allocation and pointer, or via a function with stack allocation (which is OK with move semantics).
Both of them inspired me to this solution, which is similar to #Caleth's as I found it more simple and straightforward:
template <typename T, typename... Args>
T create(Args&&... args)
{
T t(forward<Args>(args)...);
t.init();
return t;
}
class Base {
public:
virtual ~Base() = default;
Base(const Base& rhs) = default;
Base(Base&& rhs) = default;
Base& operator=(const Base& rhs) = default;
Base& operator=(Base&& rhs) = default;
template <typename T, typename... Args>
friend T create(Args&&... args);
protected:
Base() : _arg(0)
{
cout << "Base::Base()" << endl;
}
Base(int arg) : _arg(arg)
{
cout << "Base::Base(int)" << endl;
}
virtual void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
private:
int _arg;
};
class Derived : public Base {
public:
virtual ~Derived() = default;
template <typename T, typename... Args>
friend T create(Args&&... args);
protected:
Derived() : Base()
{
cout << "Derived::Derived()" << endl;
}
Derived(int arg) : Base(arg)
{
cout << "Derived::Derived(int)" << endl;
}
void init() override
{
cout << "Derived::init" << endl;
Base::init();
// ...
}
void check() override
{
cout << "Derived::check" << endl;
Base::check();
// ...
}
};
Usage:
cout << endl << "Base() ..." << endl;
Base b1 = create<Base>();
cout << endl << "Base(int) ..." << endl;
Base b2 = create<Base>(5);
cout << endl << "Derived() ..." << endl;
Derived d1 = create<Derived>();
cout << endl << "Derived(int) ..." << endl;
Derived d2 = create<Derived>(10);
Output:
Base() ...
Base::Base()
Base::init
Base::check
Base(int) ...
Base::Base(int)
Base::init
Base::check
Derived() ...
Base::Base()
Derived::Derived()
Derived::init
Base::init
Derived::check
Base::check
Derived(int) ...
Base::Base(int)
Derived::Derived(int)
Derived::init
Base::init
Derived::check
Base::check
Any other suggestions?
Personally, I just won't let anyone construct those objects directly. If their initialization is brittle, there should be another object holding them, and initializing them in its own constructor. I'd do it via the key-pass idiom.
class BaseHolder;
class Base {
private:
void init() {
// do more things
}
friend class BaseHolder;
protected:
class BuildToken {
explicit BuildToken() {}
friend class BaseHolder;
};
Base(BuildToken) {
// do your thing.
}
};
template<typename>
struct MakeType{};
template<typename T>
inline constexpr MakeType<T> make{};
class BaseHolder {
std::unique_ptr<Base> managed;
public:
template<typename T>
BaseHolder(MakeType<T>) : managed(new T(Base::BuildToken())) {
managed->init();
}
};
Now no derived class may call init itself, nor may it be called anywhere besides by Base and BaseHolder. All a derived class has to do is define a c'tor that accepts a BuildToken and forwards it to the base. However, derived classes cannot default initialize BuildToken objects themselves, they can only copy them to forward onto their base. The only place the token can be created is in BaseHolder. This is also the only place where init will be called at the proper time.
The utility MakeType is there for making BaseHolder declaration easier on the eyes, to look like this:
BaseHolder item(make<Derived>);
Don't have any public constructor, but instead have (friend) make_base and make_derived factory functions, which call init on a fully constructed object.
class Base {
public:
virtual ~Base() = default;
Base(const Base &) = default;
Base(Base &&) = default;
Base& operator=(const Base &) = default;
Base& operator=(Base &&) = default;
friend Base make_base() { Base b; b.init(); return b; }
protected:
virtual void init()
{
cout << "Base::init" << endl;
check();
// ...
}
virtual void check()
{
cout << "Base::check" << endl;
// ...
}
Base()
{
cout << "Base::Base" << endl;
}
};
class Derived : public Base {
friend Derived make_derived() { Derived b; b.init(); return b; }
protected:
Derived() : Base()
{
cout << "Derived::Derived" << endl;
}
void init() override
{
Base::init();
cout << "Derived::init" << endl;
// ...
}
void check() override
{
Base::check();
cout << "Derived::check" << endl;
// ...
}
};
init() can contain virtual functions inside, but since it should be called only in the final constructor, it should not cause
any harm.
Even if it's called through the final constructor any of the vtables for calling these virtual functions aren't initialized at that point.
So you can't guarantee the correct intended behavior.
See more elaborations of the problem here please:
Calling virtual functions inside constructors
In the following code, how can I access Base::g() from pBase? (and still get "pBase->g();" to work as it does below)
#include <iostream>
using namespace std;
class Base
{
public:
virtual void f(){ cout << "Base::f()" << endl; }
virtual void g(){ cout << "Base::g()" << endl; }
void h(){ cout << "Base::h()" << endl; }
};
class Derived : public Base
{
public:
void f(){ cout << "Derived::f()" << endl; }
virtual void g(){ cout << "Derived::g()" << endl; }
void h(){ cout << "Derived::h()" << endl; }
};
int main()
{
Base *pBase = new Derived;
pBase->f();
pBase->g();
pBase->h();
Derived *pDerived = new Derived;
pDerived->f();
pDerived->g();
pDerived->h();
return 0;
}
Output is:
Derived::f()
Derived::g()
Base::h()
Derived::f()
Derived::g()
Derived::h()
Also, is Derived::f() exactly the same as Derived::g()? (ie. automatically defined as virtual?)
Use pBase->Base::g(); to force the call of g in Base.
Yes, Derived::f is virtual. I personally find the re-emphasising of virtual to be in poor taste. Since C++11, you can use the override specifier on overridden functions, and then a compiler issues a diagnostic if virtual is dropped from the base class.
I have an pure virtual base class and a derived class. I know I am allowed to implement a virtual (not pure) method in the base class.
What I do not understand is why I HAVE to also implement the same method in the derived class if what I want is simply to use the base implementation:
#include <iostream>
using namespace std;
class Abstract {
public:
int x;
Abstract(){
cout << "Abstract constructor" << endl;
x = 1;
}
virtual void foo() = 0;
virtual void bar(){
cout << "Abstract::bar" << endl;
}
};
class Derived : Abstract {
public:
int y;
Derived(int _y):Abstract(){
cout << "Derived constructor" << endl;
}
virtual void foo(){
cout << "Derived::foo" << endl;
}
virtual void bar(){
Abstract::bar();
}
};
int main()
{
cout << "Hello World" << endl;
Derived derived(2);
derived.foo();
derived.bar(); //HERE I HAVE TO DEFINE Derived::bar to use it
return 0;
}
You don’t have to do that. You can do the following:
class Derived : public Abstract {
That way, you can use the public methods from the base class.