I am trying to find a way to access a function of the derived class through the base pointer without dynamic casting. I have tried the visitor pattern as suggested in this post, but it seems like it does not work for templated Derived class. Here is what I have:
#include <iostream>
#include <memory>
class Base
{
public:
virtual print() = 0;
};
template<class T>
class Derived final : public Base
{
private:
T value;
public:
Derived() = default;
explicit Derived(const T& data) : value{data} {}
T get_value () {return this->value;}
void print() {std::cout << value << std::endl;}
~Derived() {}
};
int main()
{
std::shared_ptr<Base> ptr_one = std::make_shared<Derived<int>>(3);
std::shared_ptr<Base> ptr_two = std::make_shared<Derived<int>>(3);
auto value = ptr_one->get_value(); // This will cause an error.
auto value_2 = ptr_two->get_value() // This will cause an error.
std::cout << value == value_2 << std::endl; // This is my final goal. Being able to compare the underlying data.
return 0;
}
My final goal is being able to compare the underlying data of two instances of the Derived class. Is there any way to achieve such task?
I struggle with the complexity of conversions and casting, and I can't find advice online that clearly guarantees efficient conversion on function return. I have two classes, Base and Derived, where Derived has no extra data members over Base. I have a named constructor for the base class that I want to return using RVO and cast to an object of the derived type with as little overhead as possible.
class Base {
public:
static Base namedConstructor(int n){
return Base(n);
}
protected:
Base(int n) : member(n){
}
int member;
};
class Derived : public Base {
static Derived nC2(int n) {
Derived derived = namedConstructor(n);
// Error: no suitable user-defined conversion from "Base" to "Derived"...
// modify derived
return derived;
}
};
Is there a way to fix the error that satisfies all the following requirements?
No use of RTTI. Dynamic casting seems unnecessary.
Only one definition of namedConstructor in case I need to modify it. If necessary, I can make it a template, but I am interested in the alternatives.
namedConstructor should take advantage of RVO in nC2.
The conversion should not silently fail if I add or remove data members from either the base or the derived class (something similar to reinterpret_cast may do this).
Add a private ctor. to Derived, which constructs it from a Base:
Derived(const Base& base) : Base(base) {
}
If later you add extra member variables to Derived, initialize them also.
This is standard-compliant (although a little bit weird), and will be optimized away in release builds.
I've added constructors and with g++ 3.0 there is copy elision:
class Base {
public:
static Base namedConstructor(int n){
return Base(n);
}
protected:
Base(int n) : member(n){
std::cout << "Create Base" << std::endl;
}
Base (const Base & b) : member (b.member) {
std::cout << "Copy Base" << std::endl;
}
int member;
};
class Derived : public Base {
public:
Derived () : Base (0) {
std::cout << "Create Derived" << std::endl;
}
Derived (const Base & b) : Base(b) {
std::cout << "Create Derived from base" << std::endl;
}
int val () { return member; }
static Derived nC2(int n) {
return namedConstructor(n); //derived;
}
};
int main ()
{
Derived d = Derived::nC2(1);
std::cout << "Value: " << d.val() << std::endl;
return 0;
}
The output from this is:
Create Base
Copy Base
Create Derived from base
Value: 1
so one Base creation, one copy of Base when creating Derived and the Derived itself.
There are no copies from namedConstructor exit or nC2, nor for the assignment in main.
I've compiled this with -O0 but with those so small functions may be there is optimization here and those are removed.
In the following example, a upcast with a static_cast will fail to compile:
class B {
public:
virtual const void func() = 0;
};
template <typename T>
class TB {
public:
virtual const void func() = 0;
T var;
};
class D : public TB<double> {
public:
const void func() {
std::cout << var << std::endl;
}
};
int main() {
D *pd = nullptr;
B *pbs = static_cast<B*>(pd); // Fails
B *pbd = dynamic_cast<B*>(pd);
}
with the error:
error: invalid static_cast from type ‘D*’ to type ‘B*’ in B *pbc = static_cast(pd);
Live example
What is the explanation for this error?
You are getting that error because D isn't actually derived from B, because you forgot to make TB derive from B.
The dynamic cast, however, still compiles because dynamic_cast can do "sideways" casts as well---the cast can actually succeed if the D object is a subobject of some derived class that is also derived directly or indirectly from B. In your example, however, this is not the case, so the cast will just fail at runtime (by returning a null pointer).
class Base1
{
public:
virtual ~Base1(){}
virtual void whatever()
{
cout << "whatever" << endl;
}
};
class Base2
{
public:
virtual ~Base2(){}
virtual void aFunc(int i) = 0;
};
class A : public Base1, public Base2
{
public:
A()
{}
~A()
{}
virtual void aFunc(int i) final
{
cout << "func" << endl;
}
};
int main()
{
void* a;
a = new A();
(static_cast<Base2*>(a))->aFunc(0);
Base2* ptr = static_cast<Base2*>(a);
ptr->aFunc(0);
return 0;
}
This example prints out "whatever" instead of "func", if I change the line with void* to A* than it prints out "func". Is this a known behavior? I would expect that's the case just don't know why.
Is this a known behavior?
Yes. Behaviour is well-defined if you convert to void* and then back to the same type. It's undefined if you convert back to a different type.
I would expect that's the case just don't know why.
There's no guarantee that a base sub-object has the same address as the complete object; in fact, if there's more than one non-empty base class, then at least one sub-object will have to be at a different address. So a valid conversion from A* to Base2* probably needs to adjust the value of the pointer, not just reinterpret it as a different type. Conversion to void* and back can't make that adjustment.
when running the following code on MSVC 2013, x64 Debug config, it will show up a message box with this famous error message when quitting the main() function
"Run-Time Check Failure #2 - Stack around the variable 'tmp' was corrupted.".
The question I can't answer is: Why?
note that no error message will occur when running on Release config. (why?)
disclaimer: this is just a sample code, meaning that I'm trying to use this same design on other classes (one base and several derived) with much more methods and template arguments and with a much more complex data type than the basic int*.
#include <iostream>
template <class T>
class base {
public:
base() {
static_cast<T*>(this)->setData();
}
~base() {
static_cast<T*>(this)->destroyData();
}
void print() {
static_cast<T*>(this)->print_int();
}
};
class derived : public base<derived> {
public:
void setData() {
x = new int();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private:
derived() {}
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
EDIT:
#Yakk if I understand correctly, you propose as solution this code:
#include <iostream>
template <class T>
class mix_in : public T
{
public:
mix_in() { (this)->setData(); }
~mix_in() { (this)->destroyData(); }
void print() { (this)->print_int(); }
};
class foo
{
public:
void setData()
{
x = new int();
}
void destroyData()
{
delete x;
x = nullptr;
}
void print_int()
{
std::cout << "x = " << *x << std::endl;
}
foo() {}
private:
int *x;
};
int main()
{
mix_in<foo> tmp;
tmp.print();
return 0;
}
It works just fine, thank you. I'll probably use this pattern since it seems that there's no solution to use CRTP for what I'm trying to do.
But I still would like to understand why the stack corruption happens. In spite of all the discussion around use or not use CRTP for all things, I'd like to understand very precisely why it happens.
Thank you again.
As for your code shown in main():
int main() {
base<derived> tmp;
tmp.print();
return 0;
}
base<derived> tmp; that's wrong usage of this pattern, you wanted derived tmp;.
The point of the CRTP is that the derived class is injected to the base class and provides implementations for certain features that are resolved at compile time.
The base class is inherently intended, to be instantiated exclusively via inheritance. Thus you should ensure not to have any instantiations outside an inheritance context.
To avoid users of your implementation trapped by this misconception, make base's constructor(s) protected:
template <class T>
class base {
public:
~base() {
static_cast<T*>(this)->destroyData();
}
// ...
protected:
T* thisPtr;
base() : thisPtr(static_cast<T*>(this)) {
}
};
NOTE: The base class shouldn't call any methods dependent on the fully initialized derived class methods from within your base class constructor though, as you have shown with your sample (static_cast<T*>(this)->setData();)!
You may store the reference to T* for later use though, as shown in the above sample.
class derived : public base<derived> {
public:
derived() {
setData();
}
void destroyData() {
delete x;
x = nullptr;
}
void print_int() {
std::cout << "x = " << *x << std::endl;
}
private: // ????
derived(const derived& other) {}
inline derived& operator= (derived copy) {}
int *x;
};
Also it's a bit unclear, why you want to hide copy constructor and assignment operator for your class?
tmp is a base<derived>, not a derived. The point of CRTP is that the base class "knows" the object's actual type because it's being passed as the template parameter, but if you manually create a base<derived>, then the base class functions would think the object is a derived, but it isn't - it's just a base<derived>. Weird things (undefined behavior) happen as a result. (As noted in the other answer, you are also printing out something without setting it...)
As to your second question, the checks generated by MSVC to detect those sorts of programmer errors appears to be turned off in Release mode, presumably for performance reasons.
template <class T> class mix_in:public T {
public:
base() { (this)->setData(); }
~base() { (this)->destroyData(); }
void print() { (this)->print_int(); }
};
Rename derived to foo. Do not inherit from mix_in or base in foo.
Swap base for mix_in in main.
CRTP is not the solution to all problems.
You say in comments,
the derived class will never be instantiated, its constructor is never called
Others have already pointed out the undefined use of an unconstructed object. To be specific, consider that int *x is a derived member, and your base<derived> usage generates calls, in sequence, to derived::set_data(), derived::print_int(), and on exit derived::destroy_data(), all member functions of an object that doesn't exist, referring to a member for which you've never allocated space1.
But I think what you're after is wholly legitimate. Factoring code is the whole point of templates and inheritance, i.e. to make important code easier to even identify let alone comprehend, and any later refactoring easier to do, by abstracting out boilerplate.
So:
template < class T >
struct preconstruction_access_subset {}; // often left empty
template < class T, class S = preconstruction_access_subset<T> >
struct base : S {
base() { S::setData(); }
~base() { S::destroyData(); }
void print() { S::print_int(); }
};
// ... later ...
#include <iostream>
struct derived;
template<> struct preconstruction_access_subset<derived> {
// everything structors in `base<derived>` need
int *x;
void setData() { x = new int; }
void destroyData() { delete x; }
void print_int() { std::cout << x << '\n'; }
};
struct derived : base<derived> {
// everything no structors in any base class need to access
};
int main() {
base<derived> tmp;
tmp.print();
}
In this example print_int() isn't actually accessed during construction, so you could drop it back into the derived class and access it from `base as for "normal" CRTP, it's just a matter of what's clearest and best for your actual code.
1 That isn't the only problem, just the only one that's apparent without considering any reliance the compiler itself might need to place on the construction sequence. Think independent-name binding and potential inlining and the ways object identity morphs during {de,con}struction and compiler code factoring for all the potential template/inheritance/member-function/etc. combinations. Don't just hoist the int *x; to solve the current symptom, that would just kick the trouble farther down the road even if yours doesn't get that far yet.