My problem is this, I have a base class from which classes are derived. I have an overloaded += operator in the base class but I only want to be able to add derived classes of the same type. I do this by returning the lhs and producing a warning message if they are not the same type.
class base{
int variable;
public:
base(int v);
base & operator+=(const base & rhs);
class a: public base{
}
class b: public base{
}
base & operator+=(const base & rhs){
if(type_same(const & rhs){
variable+=rhs.variable; }
return *this
}
a first(1);
a second(5);
b third(2);
first+=second // first.variable now =6
second+=third // warning produced second.variable still = 5
I've never used dynamic cast before so my question is is it possible/advisable to a check using it and typeid to find out whether the types passed are the same. My alternative is a string constant name for each derived class.
Why have the operator+ in the base class in the first place? If you just place operator+ with the correct type into the a and b class, it will work, without any dynamic_cast.
dynamic_cast is usually a hint that your types are not well designed and should be avoided. In the described scenario, you can surely get by without any dynamic_cast. If not, then a and b should not be derived from base, as they do behave differently. Think about it from the user perspective: By deriving a from base, you tell the user that a can be used as base. If a method requires the actual type, move it down instead of putting it into the base interface.
The correct usage btw. would be to dynamic_cast the rhs to the current type (i.e. dynamic_cast<b*>(&rhs)) and if that returns a non-zero value, then rhs was indeed of the correct type (however, think about what happens if there is a class derived from b being passed in!)
To solve the problem that you stated in your post, dynamic_cast and RTTI are definitely the right tools. However, issuing a warning at runtime while providing compile-time support for a '+' operation may point to issues in the design where the users of your API would not expect exactly the behavior that your API provides.
My take: you could employ CRTP
The below code will issue the type mismatch error at compile time, as suggested by others.
template <typename Derived>
class base{
int variable;
public:
base(int v) { variable = v; }
Derived& operator+=(const Derived& rhs);
};
struct a: base<a> {
a(int v): base<a>(v) {}
};
struct b: base<b> {
b(int v): base<b>(v) {}
};
template <typename Derived>
Derived& base<Derived>::operator+=(const Derived& rhs)
{
variable += rhs.variable;
return static_cast<Derived&>(*this);
}
int main(int argc, const char *argv[])
{
a a1(1), a2(2);
b b1(1), b2(2);
a1 += a2;
b1 += a2; // compile time error :)
return 0;
}
Even if you really wanted to type the operator arguments as base& you'd at least gain the benefit of using static_cast<> because the conversion is exact and well defined at runtime. I can expand the idea in a few
Related
Why static_case conversion from base class to derived works inside base class, but doesn't work outside the base class
#include <iostream>
using std::cout;
class Base
{
public:
template <typename T>
int getValue() const { return static_cast<const T&>(*this).getValue(); }
};
class Derived: public Base
{
public:
Derived(int v): value(v) { }
int getValue() const { return value; }
int value;
};
class Another
{
int getValue() const { return 5; }
};
template <typename T>
void out(const Base & base) {
cout << base.getValue<T>() << '\n';
}
int main() {
Derived d(5);
Base b;
out<Derived>(d); //understandable, d has derived part.
out<Derived>(b); //don't understand, b is only base.
out<Another>(b); //compile time error
//static_cast<Derived>(b); //compile time error
}
I read this article about CRTP and stumble upon this code:
template <typename T>
class Base
{
public:
void doSomething()
{
T& derived = static_cast<T&>(*this);
use derived...
}
};
class Derived : public Base<Derived>
{
...
};
And I do not clearly understand how conversion works here too.
The static_cast conversion shall be used only if this conversion is legal. In your code you are creating an object of class Base, and you are trying to convert it to the class Derived. Luckily to you the implementation of the Derived::getValue() doesn't use any data members, and returns a value from literal. Anyway that is undefined behavior.
In case of CRTP no instance of Base class is created: only instances of the Derived are used.
Upd. Try this:
//static_cast<Derived>(b); doesn't compile
static_cast<Derived&>(b); shall compile
Upd 2. You get junk because the Derived::getValue() uses a data member (in your initial version of code data members were not used).
This is part of the rules of C++. static_cast can be used to convert a base class expression to derived class. If , at runtime, the object is not actually a base class subobject of a derived class object then it is undefined behaviour with no diagnostic required.
The first sentence of your question is incorrect, this cast can be written at any point of the code.
out<Another>() fails to compile because Another is not related by inheritance to Base.
Last cast in main() is incorrect syntactically and not equivalent to code in template, you can't upcast object to object (you can downcast through, causing type contraction). In templates above you cast references.
Derived& can be bound to Base&, static_cast have no way to check it. CRTP ensures it, because this point at storage of Derived type, *this results in reference that can be safely cast to Derived& reference object.
Reference to Another can't be bound to reference to Base, when Base is not base class of Another. In that case casting pointers or references using static_cast is illegal.
Template code is legal, in case of CRTP works because template code is instatiated where Derived is comlete enough type, i.e. where template was used. Template itself doesn't generate anything and isn't compiled, only checked for correctness.
Still, in CRTP some things won't be possible, e.g. to use inside of Base class nested type declarations from Derived class as complete types, for a simple reason : they are not complete and are not subject for forward lookup, unlike member variables and functions. If such use required, then a third type has to be defined before Base, contsining required declarations.
I'm looking for an elegant solution to the following "problem":
Consider the classes Base and Child, and the way operator+ works here:
class Base
{
public:
Base(int a=0) : mValue(a) {};
Base(const Base& rhs) : mValue(rhs.mValue) {};
Base& operator=(const Base& rhs) {
if (this==&rhs) return *this;
mValue=rhs.mValue;
}
friend const Base operator+(Base &lhs, Base &rhs);
private:
int mValue;
};
const Base operator+(Base &lhs, Base &rhs)
{
Base result(lhs.mValue+rhs.mValue);
return result;
}
class Child : public Base
{
public:
Child(int a=0) : Base(a) {};
};
int main()
{
Child a(2);
Child b(5);
Child c(a+b); // **** This line ****
Child d;
d=(a+b); // **** or this other one ****
}
The marked lines in main give the error:
cannot convert from 'const Base' to 'Child'
I understand perfectly that the operator has been defined in the Base class, and returns an object of type Base, which can't be converted to Child.
One solution is overloading operator+ for the Child class, but I am wondering whether there is a better, less costly method. I'm under the impression that I'm forgetting a much easier option. Thanks!
you can define a constructor Child(Base& obj) then Child c=(a+b); statement will be fine and then you can use the base object as per your requirement.
There is no easier option.
Operator overloading and class hierarchies don't really like to mix. I'm personally very suspicious when a type that should be a value type (or else why are you overloading operators?) is part of a hierarchy. Can you describe your actual architecture? Does it actually make sense to overload the operator there?
If you want to build a child from a base without adding the appropriate constructor, there is another alternative. You can declare the casting operator in your base class, returning your mValue :
operator int() const;
This way, the compiler will do the job implicitly.
PS : Ensure const-correctness of your additive operator :
friend Base operator+(const Base &lhs, const Base &rhs);
It is easier to explain on an example so,
class base {
//....
}
class derived1 : public base {
//...
}
In my library, there is a pointer of base class. The user of the library have to make classes derived from either base or derived1 and assign pointer to that class.
How can I check what class is user-defined class derived from?
I have some remarks on the proposed compile-time x runtime solutions. In addition to when they are evaluated, is_base_of and dynamic_cast have different requirements and their answers can be different.
(1) First of all (as pointed out by others) to use dynamic_cast, base and derived classes must be polymorphic (must have at least one virtual method). is_base_of doesn't require the types to be polymorphic.
(2) The operands of is_base_of are both types whereas dynamic_cast needs a type (inside < >) and an object (inside ( )).
(3) dynamic_cast and is_base_of can give different answers (or one can compile while the other doesn't) depending on the type of inheritance (public vs protected or private). For instance consider:
struct B { virtual ~B() {} }; // polymorphic, so it can be used in a dynamic_cast
struct D1 : public B {}; // polymorphic by (public) inheritance
struct D2 : private B {}; // polymorphic by (private) inheritance
D1 d1;
D2 d2;
We have
static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");
assert(dynamic_cast<B*>(&d1));
assert(!dynamic_cast<B*>(&d2)); // Notice the negation.
Actually the last line yields a compiler error in GCC (error: 'B' is an inaccessible base of 'D2'). VS2010 does compile it (yielding just a warning similar to GCC's error message).
(4) The requirements on the classes being polymorphic can be relaxed through an exception handling trick. Consider:
struct B { }; // not polymorphic
struct D1 : public B {}; // not polymorphic
struct D2 : private B {}; // not polymorphic
D1 d1;
D2 d2;
template <typename B, typename D>
const B* is_unambiguous_public_base_of(const D* obj) {
try {
throw obj;
}
catch (const B* pb) {
return pb;
}
catch (...) {
}
return nullptr;
}
Then we have
static_assert(std::is_base_of<B, D1>::value, "");
static_assert(std::is_base_of<B, D2>::value, "");
assert((is_unambiguous_public_base_of<B>(&d1)));
assert(!(is_unambiguous_public_base_of<B>(&d2))); // Notice the negation.
It's worth mentionning that is_unambiguous_public_base_of is far slower than dynamic_cast and (this became more obvious after the renaming mentioned in the update below) always returns a nullptr for downcasts:
B* b1 = &d1;
assert(dynamic_cast<D1*>(b1)); // Requires D1 and B to be polymorphic.
assert(!(is_unambiguous_public_base_of<D1>(b1))); // Notice the negation.
A bit outdated reference on this trick is available in the following links:
Part 1, Part 2 and code
Disclaimer: the implementation of is_unambiguous_public_base_of above is just a draft to make the point and it doesn't handle const and volatile qualifications properly.
Update: In a previous version of this post is_unambiguous_public_base_of was named my_dynamic_cast and this was a source of confusion. So I renamed it to a more meaningful name. (Thanks to Jan Herrmann.)
You could use dynamic_cast.
if (dynamic_cast<DerivedClass*>(ptr)) {
std::cout << "Class is derived from DerivedClass.";
}
Check if class is derived from a specific class (compile time)
You can use std::is_base_of:
#include <type_traits>
....
const bool isBase = std::is_base_of<base, TheOtherClass>::value;
isBase is true if TheOtherClass is derived from base.
I think the answer to this question is very difficult. Of course there is std::is_base_of and dynamic_cast. Both provide you with some very limited information. The third option is function overloading. With all of those techniques you can choose a special path in your code which should be executed.
std::is_base_of can be interpreted in a boolean context and it is derived from either std::true_type or std::false_type. This fact makes it possible to use it as paramter for a function and use compile time polymorphism via function overloading. This first example shows how to use it in a boolean context, but you don't have any further specific type information. So compilation will fail in most circumstances (see here for a further description):
template<class T>
void do_it1(T const& t) {
if (std::is_base_of<T,derived1>::value) {
// we have a derived1
} else {
// we have a base
}
}
The second version is simple function overloading. Here compile time polymorphism is used but all runtime type information is lost (except virtual functions and dynamic_cast are used):
void do_it2(Base const& b) {
// we have a base your algorithm for base here
}
void do_it2(Derived2 const& d) {
// Derived algorithm here
}
Now the third version combines both:
template<class T>
void do_it3_impl(T const& t, std::true_type) {
// here t will be of a type derived from derived1
}
template<class T>
void do_it3_impl(T const& t,std::false_type) {
// here t will be of type not derived from derived1
}
template<class T>
void do_it_3(T const& t) {
do_it3_impl(t, std::is_base_of<T,derived1>()); // here we forward to our impl
}
The third variant is normaly used for header only libraries which don't use runtime poylmorphism (search for std::advance for an excample).
Now to runtime polymorphism. Here you have the dynaminc_cast variant:
void do_it4(Base const* ptr)
if (derived1 const* obj = dynamic_cast<derived*>(ptr)) {
// here we have obj with type derived1*
} else {
// here we have only base
}
If this variant is not fast enough you can implement your onw cast to derived1:
class derived1;
class base {
// as above
public:
virtual derived1 const* to_derived1() const {
return 0;
}
};
class derived1
: public base
{
// ...
virtual derived1 const* to_derived1() const {
return this;
}
};
void do_it5(Base const* ptr)
if (derived1 const* obj = ptr->to_derived1() {
// here we have obj with type derived1*
} else {
// here we have only base
}
This is fast but it scales very well for only very few (approximately 1) derived classes.
Last but not least you should think about your class design and deside what methods to make virtual and implement in base, derived1 or other classes. You should definitly look for strategy pattern.
You can do this in several ways. The most common ones as the others have pointed out are dynamic_cast<> and std::is_base_of. The latter is used at compile time, while dynamic_cast<> can be used at runtime.
HOWEVER, dynamic_cast<> will only work if your source class is polymorphic (i.e. has at least one virtual function - it can be a method or its destructor). If not, the compiler will trigger an error.
The compiler will only accept pointers to classes derived from your base class if your library functions takes pointers to the base class. My answer is with a classical approach type safety will handle it. To my experience that kind of type checking is enough. Having 25 years experience in the industry I question the need to do this check. Maybe such a fundamental question is not welcome? I would like to see the justification to having the need to do this kind of upcast. I never have to do that. The opposite, i.e. a down cast I need quite frequently.
I have a base container class, which has a number of operators (=,+,-,+=,etc). It is expected that the logic of the operators will not need to be changed for the derived classes. Thus, ideally, I would like to use the base class operators for all of its derived classes without having to redefine them for each of the derived classes explicitly (with the exception of the assignment operator).
A solution that I came up with is demonstrated below based on a simple example. The solution seems to work, but I have doubts about the validity of the method for more complicated cases. Do you think it is valid to use this assignment "hack" in class B? What are the potential pitfalls of this method? Is there anything I missed? Are there easier ways of achieving the functionality that I need (i.e. using base class operators for derived classes)?
class A
{
protected:
int a;
public:
A(int ca)
{
a=ca;
}
A(const A& A1)
{
a=A1.a;
}
int geta() const
{
return a;
}
void seta(int ca)
{
a=ca;
}
const A& operator=(const A& A1)
{
a=A1.a;
return *this;
}
};
const A operator+(const A& A1, const A& A2)
{
A myA(A1.geta()+A2.geta());
return myA;
}
class B: public A
{
public:
B(int a): A(a) {}// ... using A::A;
const B& operator=(const B& B1)
{
a=B1.geta();
return *this;
}
const B& operator=(const A& B1)
{
a=B1.geta();
return *this;
}
};
int main()
{
B myB(4);
A myA(3);
//need this to work
myB=myB+myB;
cout << myB.geta();
myA=myA+myA;
cout << myA.geta();
int j;
cin >> j;
}
For the example given i don't see any problems that can happen. Of cause you can improve the code, first by returning non const reference in operator=, second i think by adding += op to your class, and using it's code inside global operator+ function.
But in general i think it should work fine. As for assignment operators - as soon as you have only POD types and no pointers, or references or handles you don't really need any.
It will become more complicated, however when pointers appear. You'll need to make sure you copy objects, pointed by them, or manage them some other way.
And you probably will not need to modify your operators as long as you don't add more members to derived classes, which also should take part in calculations.
In general you don't have to redefine functions in the base class for derived classes. With public inheritance your derived classes will have access to those functions and use their operation just fine. If you do want to re-define them (= operator for example), be sure you call the right one (virtual functions help in this case).
I ask this question following the issue I raised here.
The point is quite simple. Suppose you have two classes of this kind:
template < class Derived >
class Base {
...
operator const Derived&() const {
return static_cast< const Derived& >(*this);
}
...
};
class Specialization : public Base<Specialization> {
...
};
Then suppose you have a type conversion like this one:
template < class T >
functionCall( const Base<T>& param) {
const T & val(param);
...
}
The question is: what should be the standard conforming behavior of this conversion?
Should it be the same as const T & val(static_cast<const T &> (param) ) or should it recursively iterate until stack overflow? Notice that I obtain the first behavior compiling with GNU g++ and the second compiling with Intel icpc.
I already tried to peek at the standard (section 5.9 on static_cast and section 12.3 on conversions) but due to my lack of experience I was not able to figure out the answer.
My many thanks in advance to anybody taking the time to help me out with this.
Looking at [expr.static.cast] in n3337 (first working draft after the Standard):
2/ An lvalue of type “cv1 B,” where B is a class type, can be cast to type “reference to cv2 D,” where D is a class derived (Clause 10) from B, if a valid standard conversion from “pointer to D” to “pointer to B” exists [...]
4/ Otherwise, an expression e can be explicitly converted to a type T using a static_cast of the form static_cast<T>(e) if the declaration T t(e); is well-formed, for some invented temporary variable t [..]
Therefore, I would interpret that gcc's behavior is the correct one, ie the expression:
static_cast<Derived const&>(*this)
should not invoke recursively operator Derived const& () const.
I deduce this from the presence of the Otherwise keyword which implies an ordering of the rules. The rule 2/ should be tried before the rule 4/.
The use of implicit conversion operators is not recommended. In C++11 you can add the keyword explicit not only to single argument constructors, but also to conversion operators. For C++03 code, you could use an explicitly named conversion function such as self() or down_cast().
Furthermore, you seem to be using the Base class for CRTP, i.e. to enable static polymorphism. That means that you have to know at compile-time which particular Derived class you are calling. Therefore, you should not have to use const Base& references in any public code, except to implement a CRTP interface.
In my projects, I have a class template enable_crtp:
#include <type_traits>
#include <boost/static_assert.hpp>
template
<
typename Derived
>
class enable_crtp
{
public:
const Derived& self() const
{
return down_cast(*this);
}
Derived& self()
{
return down_cast(*this);
}
protected:
// disable deletion of Derived* through Base*
// enable deletion of Base* through Derived*
~enable_crtp()
{
// no-op
}
private:
// typedefs
typedef enable_crtp Base;
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
const Derived& down_cast(const Base& other) const
{
BOOST_STATIC_ASSERT((std::is_base_of<Base, Derived>::value));
return static_cast<const Derived&>(other);
}
// cast a Base& to a Derived& (i.e. "down" the class hierarchy)
Derived& down_cast(Base& other)
{
// write the non-const version in terms of the const version
// Effective C++ 3rd ed., Item 3 (p. 24-25)
return const_cast<Derived&>(down_cast(static_cast<const Base&>(other)));
}
};
This class is privately derived from by any CRTP base class ISomeClass like this:
template<typename Impl>
class ISomeClass
:
private enable_crtp<Impl>
{
public:
// interface to be implemented by derived class Impl
void fun1() const
{
self().do_fun1();
}
void fun2()
{
self().do_fun2()
}
protected:
~ISomeClass()
{}
};
The various derived classes can implement this interface in their own specific way like this:
class SomeImpl
:
public ISomeClass<SomeImpl>
{
public:
// structors etc.
private:
// implementation of interface ISomeClass
friend class ISomeClass<SomeImpl>;
void do_fun1() const
{
// whatever
}
void do_fun2()
{
// whatever
}
// data representation
// ...
};
Outside code calling fun1 of class SomeImpl will get delegated to the appropriate const or non-const version of self() in the class enable_crtp and after down_casting the implementation do_fun1 will be called. With a decent compiler, all the indirections should be optimized away completely.
NOTE: the protected destructors of ISomeClass and enable_crtp make the code safe against users who try to delete SomeImpl* objects through base pointers.