Suppose that A derives from B. Is there a way to forbid an implicit upcast like the one in B *x = new A() by making an explicit cast necessary, for example?
There's no way to completely prevent this conversion.
You could prevent it in most places (but not in friends or members of A) using private inheritance, or by replacing inheritance with a containment or aggregation relation (where A contains an instance of or pointer/reference to B, rather then inheriting). Then a member function could simulate an explicit cast:
B * x = new A(); // not allowed
A * a = new A(); // OK
B * b = a->to_B(); // OK
But you should think about what behaviour you actually want to prevent, rather than making a perfectly normal operation require jumping through a rather odd hoop. There's almost certainly a better way to solve your specific problem.
That is not possible and against the rules of polymorphism.
Since A is derived from B, A is a B. So a cast is not needed, B is the mother class of A. Any instance of A can be changed to an instance of B.
That is what you want basically because it allows for programming towards interfaces.
Usually the interface, although interfaces don't exist in C++ , is defined via some kind of abstract class. The code is usually in a better shape if you are able to keep referring to the interface and keep away from the actual implementation of a certain interface.
You may create a wrapper class for that, something like:
template<typename T>
class MyPtr
{
public:
MyPtr(T* t) : t(t) {}
template <typename U>
MyPtr(U*) = delete;
MyPtr operator = (T* t) { this->t = t; return *this; }
template <typename U>
MyPtr operator = (U* t) = delete;
operator T* () const { return t; }
private:
T* t;
};
Live example
Related
I am creating a library which allows the user to store a pointer and later retrieve the pointer.
I have a class which stores the pointer of a generic type.
template <typename generic_type>
class A
{
public:
A() {}
A(generic_type *value) : data(value) {}
generic_type *getData()
{
return data;
}
private:
generic_type *data;
};
I want to also store the instances of these class template in a vector, so i inherited from a base class.
class B
{
};
template <typename generic_type>
class A : public B
{
...
};
class test_class
{
};
std::vector<B *> list;
// -------- example -------
// test_class *test = new test_class();
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
// list.push_back(new A<test_class>(test));
When retrieving from the list i will get a pointer to base class.
To call the functions in derived class A, it will have to be cast.
// example
B *bp = list.at(0);
A<test_class> *ap = static_cast<A<test_class> *>(bp);
I do not want the user to manually have to cast the base pointer themselves, but be able to call the getData() function in A which will return the actual data based on the generic_type.
// preferred API usage
B *bp = list.at(0); // they will get B pointer in another way but shown here for simplicity
test_class *t = bp->getData();
Looking around for calling child function from parent class, i came upon CRTP, which allowed me to call the function in A;but now i am unable to store it in a vector as B will be templated. So i derived B from another class referencing code from this post.
This allowed me to store it in a vector but i cant seem to find a way to call the function with generic return type and return it.
class C
{
public:
virtual void func() = 0;
};
template <typename derived>
class B : public C
{
public :
void func() // cant change to templated return type as virtual function cant be templated
{
derived *p = static_cast<derived *>(this);
p->getData(); // how to return the value from this ?
}
};
template <typename generic_type>
class A : public B<A<generic_type>>
{
...
};
std::vector<C *> list;
// -------- example -------
// this allows me to do
C *cp = list.at(0);
cp->func(); // will call getData() indirectly
// but am unable to get the returned data
I am not familiar with newer features or design patterns as i have not used c++ for a few years.
Is it possible to get the returned data? or is there a different method or pattern i could use to achieve the desired API usage scenario?
You will never get around the fact that the user has to specify which type they expect to receive. The compiler needs to know at compile-time what the return type of getData will be, so you have to decide at compile-time which concrete A instantiation you are operating on.
However, there is a way to make this "specifying the type" more convenient than a manual static cast: Provide an implicit conversion in B to any pointer.
class B
{
public:
virtual ~B() = default;
template<class T>
operator T*();
};
template <typename generic_type>
class A : public B
{
// ...
};
template<class T>
B::operator T*()
{
A<T>* a = dynamic_cast<A<T>*>(this);
if (!a)
return nullptr;
return a->getData();
}
// Usage:
std::vector<std::unique_ptr<B>> list;
list.emplace_back(new A<test_class>);
list.emplace_back(new A<int>);
list.emplace_back((A<double>*)nullptr);
test_class* out1 = *list[0]; // Returns the correct ptr
test_class* out2 = *list[1]; // Returns nullptr (incorrect type)
double* out3 = *list[2]; // Returns nullptr (data value is null)
https://godbolt.org/z/NT1AF8
This conversion operator assumes that, when we try to convert some object x from a B to some T*, that the dynamic type of x is A<T*>. It attempts the down-cast and returns getData() if it succeeds, or nullptr otherwise.
This works just fine in principle, you should however be aware that implicit conversions are better used sparingly or not at all - they can lead to very surprising behavior. You might also want to (SFINAE-)guard against someone creating an A<A<something>> or A<B>, because that sounds like a headache.
Getting it to work with cv specifiers (i.e. const/volatile) will require some more work (including specifying whether A<const int> should be a thing or not).
You could also take the middle route between manual static_cast and the implicit conversions above by writing a free accessor function like
template<class T>
T* getData(B& b)
{
// See operator T* implementation above.
}
which would be used like double* y = getData<double>(x);. I would prefer this solution for a library interface.
I want to know whether it is possible or not.
I have a class in one project.
class A { ...
void CreateInternal(void);
B* m_pData;
... }
void A::CreateInternal(void)
{
m_pData= new B;
}
and in other project, i add C class and want to make it in A::CreateInernal(void) like this...
void A::CreateInternal(void)
{
m_pData = new C; // ex) B is base class of C
}
Of course, i can make Class A to template class, however, i do not want it. I want to use it last. ( Suppose that dependency or other build error is free )
typename<class T>
class A { ...
void CreateInternal(void);
T* m_pData
... }
void A<T>::CreateInternal(void)
{
m_pData = new T;
}
I just want to register Class B or Class C in Class A.
Is it possible??
Thank you for your reply!
As denoted in the comments:
You don't want to make A a template class.
You the classes you want to create instances of share a common base class, which is the type of the member pointer as well (precondition for the following!).
So you can make createInternal a template function instead:
template <typename T>
void A::createInternal()
// ^^^ A still is a normal class!
{
m_data = new T();
// (will fail if T is a different type NOT inheriting
// from the base class in question)
}
Side note: Normally, if template functions are provided inside classes, you would have to implement them in the header file (typically at least, there are ways around...), if createInstance is private, though, and you don't call it from public inline functions, you can safely implement it in the source file as well as this file will be the only location the template ever is used.
You can even go a step further and allow to call all possible constructors by use of a variadic template:
template <typename T, typename ... TT>
void A::createInternal(TT&& ... tt)
{
m_data = new T(std::forward(tt)...);
// (will fail, if there is no matching constructor
// for the arguments provided)
}
OK, you now have to specify which instance you want to create:
void A::f()
{
createInternal<B>();
createInternal<C>();
}
I assume this being acceptable as you need to be able to tell somehow which type you actually want to create.
The alternative would be different functions for different classes (createInternalB, createInternalC), but that certainly is less elegant.
Side note:
Is it possible??
Even if your classes did not share a common base class, you still could store your objects created in a std::variant or, if you happen to compile pre-C++11, even in a union (but you need to take care yourself about which type actually is stored – in this respect, std::variant is just much safer, so prefer it whenever possible).
Update on new comments:
If you want to be able to create arbitrary objects within A without having to know which one actually is created, now offering two further alternatives:
In first variant you could make createInternal virtual in A (possibly even pure virtual) and then override in derived classes to provide the objects suiting your needs.
In second variant you provide an instance of some object provider class; assuming D is the base class of both B : public D and A : public D, so then the solution might look similar to this:
class A
{
public:
class ObjectProvider
{
public:
virtual ~ObjectProvider() = default;
public: virtual D* createInstance() = 0;
};
template <typename T>
class TheObjectProvider : public ObjectProvider
{
public:
D* createInstance() override
{
return new T();
}
};
A(std::unique_ptr<ObjectProvider> p)
: objectProvider(std::move(p))
{ }
private:
std::unique_ptr<ObjectProvider> objectProvider;
std::unique_ptr<D> m_data;
void createInternal()
{
m_data = objectProvider->createInstance();
}
};
Usage:
A ab(std::make_unique<A::ObjectProvider<B>());
// your own custom object provider:
class OP : public A::ObjectProvider
{
public:
C* createInstance() override { return new C(); }
};
A ac(std::make_unique<OP>());
The std::unique_ptr as parameter (although in general, it is not recommended to use smart pointers for) now has an important function: It indicates that the class will take ownership of the object passed, i. e. is a sink in Herb Sutter's wording – see his GotW91).
If you have a most commonly used data type (e. g. B), you could provide an overloaded default constructor providing an object provider for this type (or possibly the base type D, if not being abstract).
I am trying to do this
static_cast<IntrusivePtr<B>>(IntrusivePtr<A>)
where B publicly derives from A. However this gives the error
invalid conversion from A* to B*
Can anyone explain to me the problem here? I can sort of get around it by doing
static_cast<B*>(IntrusivePtr<A>.get())
Which in theory is exactly what the above error message says is not allowed. This is on GCC 4.4.7
The concept you're looking for is called type covariance - you want IntrusivePtr<T> to be covariant on T, which means that IntrusivePtr<D> is a subtype of IntrusivePtr<B> if D is a subtype of B. There are languages whose type system supports this, C++ is not one of them.
In C++, IntrusivePtr<A> and IntrusivePtr<B> are completely unrelated types, regardless of what A and B are (unless they're the same type). If you want to support that conversion, you have to support it explicitly:
template <class T>
struct IntrusivePtr {
template <class U, class = std::enable_if_t<std::is_convertible<U*, T*>::value>>
IntrusivePtr(IntrusivePtr<U> const& rhs) { ... }
};
or do what you're doing and side-step the IntrusivePtr class template.
In retrospect upon rereading the question, it seems more likely that IntrusivePtr supports the above conversion, but does an implicit cast between the two types - which is valid for derived-to-base but invalid for base-to-derived. But you can always explicitly cast from base-to-derived. That is:
struct B { };
struct D : B { };
B b;
D* d1 = &b; // error
D* d2 = static_cast<D*>(&b); // ok
IntrusivePtr<A> and IntrusivePtr<B> are completely unrelated types. So you can't cast between them statically (unless IntrusivePtr contains explicit conversion code or A and B are the same).
And note that you can't statically cast from a base to a derived class.
Here's one way how IntrusivePtr can be changed.
template <typename T>
struct IntrusivePtr {
IntrusivePtr(const IntrusivePtr& other) {
... // do the refcounting
ptr = other.ptr; // straight assignment, pointers are of the same type
}
template <typename Q,
typename = std::enable_if_t<std::is_convertible<Q*, T*>::value>>
IntrusivePtr(const IntrusivePtr<Q>& other) {
... // do the refcounting
ptr = other.ptr; // straight assignment, pointers are compatible
}
// this can only be used in explicit conversions
template <typename Q,
typename = std::enable_if_t<std::is_convertible<T*, Q*>::value>>
// must add bogus default parameter, or the compiler will complain
explicit IntrusivePtr(const IntrusivePtr<Q>& other, int=0) {
... // do the refcounting
ptr = static_cast<T*>(other.ptr); // explicit downcast, trust the programmer
}
... // other methods
T* ptr;
};
Checking:
struct A {};
struct B : A {};
IntrusivePtr<A> a;
IntrusivePtr<B> b;
a = a; // ok, straight copy
a = b; // ok, implicit upcast
b = static_cast<IntrusivePtr<B>>(a); // ok, explicit downcast
b = a; // error, implicit conversion is not allowed
However, if IntrusivePtr is not too far off boost::intrusive_ptr, it should have a function similar to boost::intrusive_ptr::static_pointer_cast. Which probably should be used instead, especially with compilers that don't support C++11.
How do you design polymorphism when you have a member which type depends on some constraints.
Say I have this :
template<typename T>
class Base
{
public:
Base() = default;
virtual ~Base() = default;
T member;
};
class DerivedA : public Base<int>
{
public:
DerivedA() {member = 5;}
};
class DerivedB : public Base<float>
{
public:
DerivedB() = default;
};
I want to be able to create a new derived object depending on different parameters, i.e :
Base *b;
if (something)
b = new DerivedA();
else
b = new DerivedB();
Obviously I can't do this since I need to provide template parameters for the declaration of b.
Is this bad design ? How do you handle this ?
I could write a small wrapper :
class Wrapper() {};
template<typename T>
class Base : public Wrapper
{
// ...
};
Wrapper a, b;
a = new DerivedA;
b = new DerivedB;
But then I won't have access directly to member or other methods declared in Base or Derived. I would need to cast : reinterpret_cast<DerivedA*>(a)->member, making polymorphism useless.
Thanks
Wrapper design should be exactly what you are looking for. The problem is that c++ is statically typed, so you can't declare member without specifying its type. The common way to avoid this is to design a base class which supports all the functionality you want, and implement a specific behaviour in derived classes, just as you did.
Probably the problem is that your class doesn't support all the functionality you need. Try to avoid using member directly and wrap its usage into virtual methods. Reimplement these methods in your derived classes.
If this is still not an option, consider methods for extracting your member. Maybe virtual getters and setters with appropriate conversions.
As a last resort, consider boost::variant, boost::any. But really they are implemented using the technique similar to your wrapper. So you get wrapper for the wrapper.
Well, if the "access" depends on the template parameter T (such reading Base.member), then you have to supply it somehow. Casting to one of the derived classes is one way to do it, but you don't need the reinterpret_cast. You need to start using pointers/references, to avoid the cut-off and let the substitutability work correctly:
Wrapper *a, *b;
a = new DerivedA;
b = new DerivedB;
int a_member = static_cast<DerivedA*>(a)->member;
float b_member = static_cast<DerivedB*>(b)->member;
And if you add a virtual method to Wrapper to make it polymorphic, you can do dynamic cast as well:
DerivedB* b_derived = dynamic_cast<DerivedB*>(b);
if (b_derived != nullptr) {
float b_member = b_derived->member;
// ...
}
I feel like this one has been asked before, but I'm unable to find it on SO, nor can I find anything useful on Google. Maybe "covariant" isn't the word I'm looking for, but this concept is very similar to covariant return types on functions, so I think it's probably correct. Here's what I want to do and it gives me a compiler error:
class Base;
class Derived : public Base;
SmartPtr<Derived> d = new Derived;
SmartPtr<Base> b = d; // compiler error
Assume those classes are fully fleshed out... I think you get the idea. It can't convert a SmartPtr<Derived> into a SmartPtr<Base> for some unclear reason. I recall that this is normal in C++ and many other languages, though at the moment I can't remember why.
My root question is: what is the best way to perform this assignment operation? Currently, I'm pulling the pointer out of the SmartPtr, explicitly upcasting it to the base type, then wrapping it in a new SmartPtr of the appropriate type (note that this is not leaking resources because our home-grown SmartPtr class uses intrusive reference counting). That's long and messy, especially when I then need to wrap the SmartPtr in yet another object... any shortcuts?
SmartPtr<Base> and SmartPtr<Derived> are two distinct instantiations of a the SmartPtr template. These new classes do not share the inheritance that Base and Derived do. Hence, your problem.
what is the best way to perform this assignment operation?
SmartPtr<Base> b = d;
Does not invoke assignment operator. This invokes the copy-ctor (the copy is elided in most cases) and is exactly as if you wrote:
SmartPtr<Base> b(d);
Provide for a copy-ctor that takes a SmartPtr<OtherType> and implement it. Same goes for the assignment operator. You will have to write out the copy-ctor and op= keeping in mind the semantics of SmartPtr.
Both the copy constructor and the assignment operator should be able to take a SmartPtr of a different type and attempt to copy the pointer from one to the other. If the types aren't compatible, the compiler will complain, and if they are compatible, you've solved your problem. Something like this:
template<class Type> class SmartPtr
{
....
template<class OtherType> SmartPtr(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> copy constructor
template<class OtherType> SmartPtr<Type> &operator=(const SmartPtr<OtherType> &blah) // same logic as the SmartPtr<Type> assignment operator
};
Templates are not covariant, and that's good; imagine what would happen in the following case:
vector<Apple*> va;
va.push_back(new Apple);
// Now, if templates were covariants, a vector<Apple*> could be
// cast to a vector<Fruit*>
vector<Fruit*> & vf = va;
vf.push_back(new Orange); // Bam, we just added an Orange among the Apples!
To achieve what you are trying to do, the SmartPointer class must have a templatized constructor, that takes either another SmartPointer or a pointer of another type. You could have a look at boost::shared_ptr, which does exactly that.
template <typename T>
class SmartPointer {
T * ptr;
public:
SmartPointer(T * p) : ptr(p) {}
SmartPointer(const SmartPointer & sp) : ptr(sp.ptr) {}
template <typename U>
SmartPointer(U * p) : ptr(p) {}
template <typename U>
SmartPointer(const SmartPointer<U> & sp) : ptr(sp.ptr) {}
// Do the same for operator= (even though it's not used in your example)
};
Depends on the SmartPtr class. If it has a copy constructor (or in your case, assignment operator) that takes SmartPtr<T>, where T is the type it was constructed with, then it isn't going to work, because SmartPtr<T1> is unrelated to SmartPtr<T2> even if T1 and T2 are related by inheritance.
However, if SmartPtr has a templatized copy constructor/assignment operator, with template parameter TOther, that accepts SmartPtr<TOther>, then it should work.
Assuming you have control of the SmartPtr class, the solution is to provide a templated constructor:
template <class T>
class SmartPtr
{
T *ptr;
public:
// Note that this IS NOT a copy constructor, just another constructor that takes
// a similar looking class.
template <class O>
SmartPtr(const SmartPtr<O> &src)
{
ptr = src.GetPtr();
}
// And likewise with assignment operator.
};
If the T and O types are compatible, it will work, if they aren't you'll get a compile error.
I think the easiest thing is to provide automatic conversion to another SmartPtr according to the following:
template <class T>
class SmartPtr
{
public:
SmartPtr(T *ptr) { t = ptr; }
operator T * () const { return t; }
template <class Q> operator SmartPtr<Q> () const
{ return SmartPtr<Q>(static_cast<Q *>(static_cast<T *>(* this))); }
private:
T *t;
};
Note that this implementation is robust in the sense that the conversion operator template does not need to know about the semantics of the smart pointer, so reference counting does not need to replicated etc.