I want to have a typedef in my base class to be specialized to each class derived from this base class. code:
template<class X>
class SharedPointer
{
public:
X* data;
SharedPtr(X *val)
{
data = val;
}
};
template<class T=Base> /* default type, I know this is a mistake.
The reason to have this here is to just indicate that the default argument
should be Base itself. so it'll have a Base type of shared pointer. */
class Base
{
public:
typedef SharedPointer<T> MyTypeOfPtr;
virtual MyTypeOfPtr Func()
{
Base *b = new Base;
return MyTypeOfPtr(b);
}
};
class Derived : Base<Derived>
{
public:
MyTypeOfPtr Func()
{
Derived *d = new Derived;
return MyTypeOfPtr(d);
}
};
main()
{
Base b;
Base::MyTypeOfPtr ptr1 = b.Func();
Derived d;
Derived::MyTypeOfPtr ptr2 = d.Func();
}
but this doesn't compile. is there a way to have this functionality?
You have to get all sorts of details right:
Spelling: "SharedPointer" or "SharedPtr"?
Templates and classes aren't the same thing, so you can't have class T = Base: T is a class, Base isn't. Also, you can't have the default refer to itself, so even class T = Base<T> doesn't work. Remove the default type.
Class inheritance is private by default, so say class Derived : public Base<Derived>.
Make the constructor of SharedPointer public.
Base::Func() makes no sense; maybe it should say new T.
I should seriously suggest that you start with simpler examples and build up slowly.
Related
class Base1{
public:
Base1(){};
virtual ~Base1() = 0;
}
class Derived1 : public Base1{
public:
Derived1(int a) : a(a){};
~Derived1();
int a;
}
class Base2{
public:
Base2(){};
virtual ~Base2() = 0;
}
class Derived2 : public Base2{
public:
Derived2(int b) : b(b){};
~Derived2();
int b;
void func(const Base1 &base1); // How to access Derived1::a here?
}
Given the above class definition, how can I access Derived1::a in void func(const Base1 &base1)? I am still new to polymorphism. I tried to use different static_cast or dynamic_cast methods but none of them works. What should I do inside the function so I can access a derived class member from a base class reference?
FYI I can't change the class definition for my coursework requirement, and that is what given to me. I understand that it is simpler to just pass Derived1 as parameter but I am not allow to do so.
Given the above class definition, how can I access Derived1::a in void func(const Base1 &base1)? ... FYI I can't change the class definition for my coursework requirement, and that is what given to me.
Ideally, you should expose a virtual method in Base1 that returns an int (or int&), and then have Derived1 override that method to return its a member.
But, given that you are not allowed to change the class definitions, that is not an option.
You need a pointer or reference to a Derived1 object in order to access its a member directly. Which really leaves you with only 1 choice - you can use dynamic_cast to typecast the base class reference to the derived class type, eg:
void Derived2::func(const Base1 &base1)
{
// this will raise an exception if the cast fails at runtime
const Derived1 &d = dynamic_cast<const Derived1&>(base1);
// use d.a as needed...
}
Alternatively:
void Derived2::func(const Base1 &base1)
{
// this will return null if the cast fails at runtime
const Derived1 *d = dynamic_cast<const Derived1*>(&base1);
if (d) {
// use d->a as needed...
} else {
// do something else...
}
}
In our legacy project we have a function that takes reference to a base class and creates a copy of the derived class on the heap. This is solved essentially like this: https://godbolt.org/z/9ooM4x
#include <iostream>
class Base
{
public:
virtual Base* vclone() const = 0;
int a{7};
};
class Derived : public Base
{
public:
Derived()
{
a = 8;
}
Base* vclone() const override
{
return new Derived(*this);
}
};
Base* clone(const Base& original)
{
return original.vclone();
}
int main()
{
Derived d1;;
auto* d2 = clone(d1);
std::cout << d2->a << std::endl;
}
This works, but I would like to get rid of the boilerplate vclone method that we have to have in every single derived class.
We have hundreds of derived classes, some of them derived not directly from Base, but from some of the other derived classes too. So if we forget to override the vclone method, we may not even get a warning of the slicing that will happen.
Now, there is much to say about such a design, but this is 10-15 year old code that I try to modernize step by step. What I do look for, is a templatized version of clone that does not depend on a virtual method. What I want, is a clone function like this:
Base* clone(const Base& original)
{
return new <Actual Derived Type>(original);
}
The actual derived type is somewhat known, since a dynamic_cast will fail if trying to cast to it with wrong type, but I don't know if it is possible to access the actual type in a way that I want.
Any help would be appreciated.
I also think you probably cannot improve the code in the sense to make it shorter.
I would say this implementation is basically the way to go.
What you could do is to change the return value of Derived::clone to Derived *. Yes C++ allows this.
Then a direct use of Derived::clone yields the correct pointer type and Base::clone still works as expected
class Derived : public Base
{
public:
Derived()
{
a = 8;
}
Derived* vclone() const override // <<--- 'Derived' instead of 'Base'.
{
return new Derived(*this);
}
};
I would also rename to vclone member function to clone (There is no need to have two names).
The free function clone could be made a template so that it works for all classes and returns the right pointer type
template <class T>
T *clone(const T *cls)
{
return cls->clone();
}
However, all these changes do not make the code shorter, just more usable and perhaps more readable.
To make it a little shorter you might use an CRTP approach.
template <class Derived, class Base>
class CloneHelper: public Base {
Derived* vclone() const override
{
return new Derived(* static_cast<Derived *>(this) );
}
};
// then use
class Derived : public CloneHelper<Derived, Base>
{
public:
Derived()
{
a = 8;
}
};
However, I am not sure if it is worth it. One still must not forget the CloneHelper, it makes inheritance always public and you cannot delegate to the Base constructor so easily and it is less explicit.
You could use an outside clone function and typeid:
#include <typeindex>
#include <string>
#include <stdexcept>
#include <cassert>
template<class Derived_t, class Base_t>
Base_t *clone_helper(Base_t *b) {
return new Derived_t(*static_cast<Derived_t *>(b));
}
struct Base {
virtual ~Base() = default;
};
struct Derived : Base {};
Base *clone(Base *b) {
const auto &type = typeid(*b);
if (type == typeid(Base)) {
return clone_helper<Base>(b);
}
if (type == typeid(Derived)) {
return clone_helper<Derived>(b);
}
throw std::domain_error(std::string("No cloning provided for type ") + typeid(*b).name());
}
int main() {
Derived d;
Base *ptr = &d;
auto ptr2 = clone(ptr);
assert(typeid(*ptr2) == typeid(Derived));
}
This will find at runtime if you did not provide a clone method. It may be slower than usual. Sadly a switch is not possible since we cannot obtain the typeid of a type at compile time.
You may like to implement clone function in a separate class template, which is only applied to derived classes when an object of a derived class is created. The derived classes do not implement clone (keep it pure virtual) to avoid forgetting to override it in a further derived class.
Example:
struct Base {
virtual Base* clone() const = 0;
virtual ~Base() noexcept = default;
};
template<class Derived>
struct CloneImpl final : Derived {
using Derived::Derived;
CloneImpl* clone() const override { // Covariant return type.
return new CloneImpl(*this);
}
};
template<class T>
std::unique_ptr<T> clone(T const& t) { // unique_ptr to avoid leaks.
return std::unique_ptr<T>(t.clone());
}
struct Derived : Base {};
struct Derived2 : Derived {};
int main() {
CloneImpl<Derived> d1; // Apply CloneImpl to Derived when creating an object.
auto d2 = clone(d1);
auto d3 = clone(*d2);
CloneImpl<Derived2> c1; // Apply CloneImpl to Derived2 when creating an object.
auto c2 = clone(c1);
auto c3 = clone(*c2);
}
See https://stackoverflow.com/a/16648036/412080 for more details about implementing interface hierarchies without code duplication.
The code below won't compile:
struct Base
{
std::vector<void(Base::*)(void)> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
Is it possible to refer derived class in template member x? In the example above I specify exactly Base and derived classes cannot push their own member functions into vector x.
Casting is bad since your code have to assume that this will be called only for instance of Derived class. This means that you either have to assume that all items in x are instance of Derived (in such case declaration of x is to general and should be changed to std::vector<void(Derived::*)(void)> x;) or you have to maintain extra information what which class method is stored in specific position of x. Both approaches are bad.
In modern C++ it is much better do do it like this:
struct Base
{
std::vector<std::function<void()>> x;
};
struct Derived : public Base
{
void foo() {}
};
// ...
Derived d;
d.x.push_back([&d](){ d.foo(); });
Another good approach can be CRTP:
template<class T>
struct Base
{
std::vector<void(T::*)(void)> x;
};
struct Derived : public Base<Derived>
{
void foo() {}
};
// ...
Derived d;
d.x.push_back(&Derived::foo);
You may, but there is no implicit conversion; it requires a cast.
Derived d;
d.x.push_back(static_cast<void(Base::*)()>(&Derived::foo));
The caveat is the if you use that pointer to member with an object that isn't really a Derived, the behavior is undefined. Tread carefully.
As an addendum, if you want to get rid of the cast when taking the pointer, you can do that by encapsulating the push (with some static type checking to boot):
struct Base
{
std::vector<void(Base::*)(void)> x;
template<class D>
auto push_member(void (D::* p)()) ->
std::enable_if_t<std::is_base_of<Base, D>::value> {
x.push_back(static_cast<void(Base::*)()>(p));
}
};
I think I would express this by calling through a non-virtual member function on the base.
example:
#include <vector>
struct Base
{
std::vector<void(Base::*)(void)> x;
// public non-virtual interface
void perform_foo()
{
foo();
}
private:
// private virtual interface for the implementation
virtual void foo() = 0;
};
struct Derived : public Base
{
private:
// override private virtual interface
void foo() override {}
};
// ...
int main()
{
Derived d;
d.x.push_back(&Base::perform_foo);
auto call_them = [](Base& b)
{
for (auto&& item : b.x)
{
(b.*item)();
}
};
call_them(d);
}
Say I have a class:
class Foo{
public:
Foo(){
}
//Is it possible to create a function like this:
virtual Foo* createOb(){
//Should create a new Foo,Bar or Fiz, depending on the actual object type.
}
}
class Bar: public Foo{
public:
Bar(){
}
}
class Fiz: public Foo{
public:
Fiz(){
}
}
Is it possible to have a method createOb() in the base class, so when createOb() is called on an instance of one of the derived classes, that an instance of the derived class is created ?
Yes, it can be done, using CRTP.
Bu first, returning a raw pointer obtained from new is very dangerous. In c++ raw pointers should be used only when they do not have ownership of the pointed object. So I took the liberty to use unique_ptr:
struct Base {
virtual auto create_obj() -> std::unique_ptr<Base>
{
return std::unique_ptr<Base>{};
}
};
// abstract works too:
struct Base {
virtual auto create_obj() -> std::unique_ptr<Base> = 0;
};
template <class Derived>
struct Base_crtp : Base {
auto create_obj() -> std::unique_ptr<Base> override /* final */
{
return std::unique_ptr<Base>{new Derived{}};
}
};
struct D1 : Base_crtp<D1>
{
};
struct D2 : Base_crtp<D2>
{
};
And then:
auto b1 = std::unique_ptr<Base>{new D1{}};
auto b2 = std::unique_ptr<Base>{new D2{}};
auto new_d1 = b1->create_obj();
auto new_d2 = b2->create_obj();
Definitely YES!!!
When a method is declared virtual in base class, and called through the derived class object, then the derived class function gets called (Read vprt, vtable concept in c++).
#include <iostream>
using namespace std;
class A{
public:
virtual A* getobj(){
return new A();
}
};
class B: public A{
public:
B(){cout<<"B constructor"<<endl;}
virtual A* getobj(){
return new B();
}
};
int main()
{
A *a = new B();
A *second = a->getobj();
return 0;
}
In the above code, we are calling the getobj() function using class B's object.
Here the constructor of class B is called twice.
first, for new B() in main
secondly for getobj function call which again creates object of B
This is not an optimal solution, but it works.
In your .h
class Foo{
public:
Foo();
virtual Foo* createOb();
};
class Bar: public Foo{
public:
Bar();
};
class Fiz: public Foo{
public:
Fiz();
};
In your .cpp
#include "Header.h"
Foo::Foo() {}
Foo* Foo::createOb(){
if (dynamic_cast<Bar*>(this)) {
return new Bar();
}
else if (dynamic_cast<Foo*>(this)) {
return new Foo();
}
return nullptr;
}
Bar::Bar() {}
Fiz::Fiz() {}
As already suggested please consider a pure virtual method
No, this is not possible with "pure" inheritance. The classes must override createOb() member function in order to support cloning.
You can see why this is not possible by considering separate compilation of classes. An implementation of one-fits-all createOb() member function must be completed in isolation from Bar and Fiz, making it impossible for the base to know the type of its subclasses.
An implementation with a pure virtual function in the base is very common, though.
Another approach is to use Curiously Recurring Template Pattern (CRTP) to implement cloning. This article explains how it can be done.
If I have a base class and a derived class, such as:
class Base {
protected:
int a;
public:
void setA(int);
void getA(int);
}
class Derived : public Base {
private:
int b;
public:
void doThing();
}
Then a third, additional class that uses the base class:
class OtherClass {
public:
Base doClassThing(Base*, Base*);
}
What's the best way to pass the derived class to a function that's defined to return a base class and take the base class as an argument. Like this:
Derived *x = new Derived();
Derived *y = new Derived();
doClassThing(x, y);
Would I pass the objects with a type cast? Or should I type cast the objects when they're first created?
To answer your two questions:
You would not cast the objects when they're first created.
There is no need to cast when calling; You do not need to modify the code in your question.