This question already has answers here:
call to pure virtual function from base class constructor
(8 answers)
Closed 5 years ago.
class a //my base class
{
public:
a()
{
foo();
}
virtual void foo() = 0;
};
class b : public a
{
public:
void foo()
{
}
};
int main()
{
b obj; //ERROR: undefined reference to a::foo()
}
Why it gives me error? The pure virtual foo is defined. What do I need to change in my code to make it work? I need pure virtual method from base class be called in its constructor.
Calling virtual functions in a constructor is recognised as a bad thing to do.
During base class construction of a derived class object, the type of
the object is that of the base class. Not only do virtual functions
resolve to the base class, but the parts of the language using runtime
type information (e.g., dynamic_cast (see Item 27) and typeid) treat
the object as a base class type.
So your instantiation of b invokes the a constructor. That calls foo(), but it's the foo() on a that gets called. And that (of course) is undefined.
Quoted from a book "Let Us C++"by Yashwant Kanetkar
It is always the member function of the current class , is called.That
is , the virtual mechanism doesn't work within the constructor
So, the foo() of class a gets called.
Since it is declared pure virtual, it will report an error
foo function is called in class a's constructor, and at that time, object b has not been fully constructed yet, hence it's foo implementation is unavailable.
Quoted from "Effective C++":
Don't call virtual functions during construction or destruction,
because such calls will never go to a more derived class than that of
the currently executing constructor or destructor
Related
This question already has answers here:
can dynamic binding happen without using pointer and using regular object in c++
(1 answer)
Where do "pure virtual function call" crashes come from?
(8 answers)
Closed 8 months ago.
It's said that in C++ constructor function, as long as the object has not finished construction, shouldn't call virtual function, or else there'll be "pure virtual function call error" thrown out. So I tried this:
#include<stdio.h>
class A{
virtual void f() = 0;
};
class A1 : public A{
public:
void f(){printf("virtual function");}
A1(){f();}
};
int main(int argc, char const *argv[]){
A1 a;
return 0;
}
compile it with g++ on windows, it works and prints
virtual function
So how to make my program throw out "pure virtual function call" exception?
Thanks!
You are not getting the "pure virtual method call" exception because A::f() is not being called.
A1's constructor is calling its own A1::f() method, which is perfectly safe to do during A1's construction.
The issue with calling a virtual method in a constructor has to do with a base class constructor calling a derived class method, which doesn't work since the derived portion of the object being constructed doesn't exist yet.
So, to get the exception you want, you need to call f() in A's constructor rather than in A1's constructor.
This question already has answers here:
call to pure virtual function from base class constructor
(8 answers)
Calling virtual functions inside constructors
(15 answers)
Closed 1 year ago.
I am trying to call an overriden function from the parent, and found out that it just crashes.
This is quite hard to describe, so here the minimal reproducible code:
#include <iostream>
class A
{
public:
A()
{
init1();
}
void init1()
{
printf("1");
init2();
printf("2");
}
virtual void init2() = 0;
};
class B : public A
{
public:
B()
: A()
{}
void init2() override
{
printf("hello");
}
};
int main()
{
B b;
return 0;
}
On MSVC 2019 it crashes, on http://cpp.sh/ it outputs "1" and then main() returns 0, but we never see "hello" or "2".
Why does it crash? What happens from a low level point of view? Is A trying to call its own init2()?
Is there a way of doing it, so I don't have to, in every derived class, add init2() in its constructor?
You can't call a derived class's overriden methods from within a base class constructor (or destructor). The derived class portion of the object doesn't exist yet.
So, to answer your questions:
yes A::A() is trying to call A::init2(), not B::init2(), and thus crashes from calling a pure virtual method.
There are ways (like via CRTP) for a base class constructor to call a derived class method, but doing so has limitations to it (ie, not being able to access any derived class data members since they still don't exist yet, only base class data members can be accessed). In your example, B::init2() doesn't access anyB data members, so it is possible for A::A() to call B::init2(), but in general you really need to wait for B to begin/finish constructing itself before you can safely call B::init2().
This question already has answers here:
Why do we need a pure virtual destructor in C++?
(11 answers)
Closed 7 years ago.
As I know in cpp, when we delete an object or when the main finishes, the destructors of all objects will be called. For those objects whose type are class child, the destructors of class child will be called first then the distructors of class parent will be called.
Now I am confused. Because if a pure virtual destructor is allowed, how could it be called when we delete an object of class child? Doesn't it call the destructor of class parent which is pure virtual?
Yes, the destructor of the base class is called. This means it must have an implementation. It is possible to provide an implementation for any pure virtual function, including the destructor. For example:
struct foo
{
virtual ~foo() = 0; // pure virtual dtor
};
foo::~foo() {} // implementation
The use-case of a pure virtual destructor is to ensure a class without any other pure virtual methods cannot be instantiated.
This question already has answers here:
C++ "virtual" keyword for functions in derived classes. Is it necessary?
(9 answers)
Closed 9 years ago.
class Base
{
virtual void foo();
}
class Derived : public Base
{
void foo();
}
It it OK?
Or it can make some problems?
I think it insist "DO NOT INHERIT FROM DERIVED".
Once you marked the foo() function in Base class as virtual it is implicitly virtual in Derived class, even if you don't mention the keyword virtual in front of it.
virtualness is inherited. Even if you do not declare an overridden method virtual, it will be virtual.
Hence, if you access an object of Derived using Base pointer or reference, it will call foo of Derived.
virtual functions are inherited automatically. So even if you don't declare it as virtual, it is virtual actually.
The reason for you to explicitly declare it as virtual is for better clarification so that anyone reading this code can instantly understand that it is a virtual functions, without having to check the base class declarations.
This question already has answers here:
Accessing protected members in a derived class
(8 answers)
Closed 9 years ago.
Am a newbie to C++.
class A
{
public:
int i;
protected: //**--- [1]**
void set()
{
i=5;
cout<<i;
}
};
class B : public A
{
public:
void call()
{
A obj;
obj.set(); //**----[2]**
set(); //**---[3]**
}
};
int main()
{
B* b_obj = new B;
b_obj->call();
}
Why doesn't the code compiled if i try including [2] and not replacing [1] to public BUT it works if i compile including [3] alone?
Compiled error: error: ‘void A::set()’ is protected.
In short, My intention is to understand why base object cannot be called in derived class if the access specifier for the base class interface is set as protected.
Not sure if my answer is correct, but here goes:
set is protected in class A. This means no outside member can access set, but derived classes can.
When calling set() by itself inside B you are calling the function as a derived function from A inside your derived class B, meaning the compiler will accept this because the function is protected (accessible to derived classes.)
However when you define A obj, calling obj.set(), in relation to the obj instance, the call is external to the class, hence why the compiler gives error.
Hope that helps.
Pet is unrelated to A or B, so whether f.set() is allowed depends on the definition of Pet. By contrast, just set() works because it's protected in the base class, and hence accessible in derived classes.