I would like to inherit from a class with the const specifier like this:
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public const Property
{
// Can never call A::set() with this class, even if
// the instantiation of this class is not const
};
class NonConstChild : public Property
{
// Can call both A::set() and A::get() depending on
// the constness of instantiation of this class
};
My compiler obviously gives me an error for the const keyword in the second classes declaration. Ideally I'd like to avoid having to create a new class ReadOnlyProperty from which ConstChild would inherit.
Can I somehow use the const keyword for inheritance?
If not, do you have any other ideas on how to solve this problem?
Introduce mutability later in your inheritance tree and derive appropriately:
class Property
{
int get() const;
};
class MutableProperty : public Property {
{
void set(int a);
};
And then:
class ConstChild : public Property { ... };
class MutableChild : public MutableProperty { ... };
I had the need for a related problem, which is: to really control/highlight mutable and const access on some class.
I did it with this simple reusable template wrapper:
template <typename T>
class TAccessor : private T
{
public:
const T& Const() const { return *this; }
T& Mutable() { return *this; }
};
// Example of use:
template <typename T>
using MyVector = TAccessor<std::vector<T>>;
void main()
{
MyVector<int> vector;
vector.Mutable().push_back(10);
int x = vector.Const()[1];
...
}
If you create a const member function set, you will get what you need.
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public Property
{
void set(int a) const {}
};
The only caveat is that a sly user can circumvent your intention by using:
ConstChild child;
child.set(10); // Not OK by the compiler
Property& base = child;
base.set(10); // OK by the compiler
I would like to inherit from a class with the const specifier"
However much you want to is irrelevant. You cannot. That is not valid C++.
Can I somehow use the const keyword for inheritance?"
No.
Use a data member or private base class instead of public base class.
Then you control the access to that member.
You can make the Property thing an abstract interface if you need polymorphic behavior.
You can use a template class and a specialization for a constant type:
template<typename T> class base_property {
protected:
T value;
};
template<typename T> class property : public base_property<T> {
public:
const T& get()const { return value; }
void set(const T& v){ value = v; }
};
template<typename T> class property<const T> : public base_property<T> {
public:
const T& get()const { return value; }
};
class ConstChild : public property<const int>{ };
I had the same need and I ended up with this quite manual approach :
class A
{
public:
void fooMutable(void) {}
void fooConst(void) const {}
};
class B : private A
{
public:
using A::fooConst;
const A& getParent(void) const
{
return *this;
}
};
void fooParent(const A&) {}
int main(void)
{
auto b = B{};
b.fooConst(); // Ok
b.fooMutable(); // Fail
fooParent(b); // Fail
fooParent(b.getParent()); // Ok
return 0;
}
Note that the using keyword would not work with overloads const/mutable :
class A
{
public:
void foo(void) {}
void foo(void) const {}
};
class B : private A
{
public:
using A::foo; // Expose the const and the mutable version
};
To solve this you could redefine the function yourself and call the parent :
class B : private A
{
public:
void foo(void) const
{
A::foo();
}
};
It can become pretty time consuming if you're inheriting a large hierarchy, but if it's for a not-so-big class it should be very reasonable and being quite natural for the user.
I have a trick, not a clean solution.
class ConstChild : private Property
{
operator const Property () { return *this; }
};
then
ConstChild cc;
cc.set(10); // ERROR
cc().get();
Related
I would like to inherit from a class with the const specifier like this:
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public const Property
{
// Can never call A::set() with this class, even if
// the instantiation of this class is not const
};
class NonConstChild : public Property
{
// Can call both A::set() and A::get() depending on
// the constness of instantiation of this class
};
My compiler obviously gives me an error for the const keyword in the second classes declaration. Ideally I'd like to avoid having to create a new class ReadOnlyProperty from which ConstChild would inherit.
Can I somehow use the const keyword for inheritance?
If not, do you have any other ideas on how to solve this problem?
Introduce mutability later in your inheritance tree and derive appropriately:
class Property
{
int get() const;
};
class MutableProperty : public Property {
{
void set(int a);
};
And then:
class ConstChild : public Property { ... };
class MutableChild : public MutableProperty { ... };
I had the need for a related problem, which is: to really control/highlight mutable and const access on some class.
I did it with this simple reusable template wrapper:
template <typename T>
class TAccessor : private T
{
public:
const T& Const() const { return *this; }
T& Mutable() { return *this; }
};
// Example of use:
template <typename T>
using MyVector = TAccessor<std::vector<T>>;
void main()
{
MyVector<int> vector;
vector.Mutable().push_back(10);
int x = vector.Const()[1];
...
}
If you create a const member function set, you will get what you need.
class Property
{
int get() const;
void set(int a);
};
class ConstChild : public Property
{
void set(int a) const {}
};
The only caveat is that a sly user can circumvent your intention by using:
ConstChild child;
child.set(10); // Not OK by the compiler
Property& base = child;
base.set(10); // OK by the compiler
I would like to inherit from a class with the const specifier"
However much you want to is irrelevant. You cannot. That is not valid C++.
Can I somehow use the const keyword for inheritance?"
No.
Use a data member or private base class instead of public base class.
Then you control the access to that member.
You can make the Property thing an abstract interface if you need polymorphic behavior.
You can use a template class and a specialization for a constant type:
template<typename T> class base_property {
protected:
T value;
};
template<typename T> class property : public base_property<T> {
public:
const T& get()const { return value; }
void set(const T& v){ value = v; }
};
template<typename T> class property<const T> : public base_property<T> {
public:
const T& get()const { return value; }
};
class ConstChild : public property<const int>{ };
I had the same need and I ended up with this quite manual approach :
class A
{
public:
void fooMutable(void) {}
void fooConst(void) const {}
};
class B : private A
{
public:
using A::fooConst;
const A& getParent(void) const
{
return *this;
}
};
void fooParent(const A&) {}
int main(void)
{
auto b = B{};
b.fooConst(); // Ok
b.fooMutable(); // Fail
fooParent(b); // Fail
fooParent(b.getParent()); // Ok
return 0;
}
Note that the using keyword would not work with overloads const/mutable :
class A
{
public:
void foo(void) {}
void foo(void) const {}
};
class B : private A
{
public:
using A::foo; // Expose the const and the mutable version
};
To solve this you could redefine the function yourself and call the parent :
class B : private A
{
public:
void foo(void) const
{
A::foo();
}
};
It can become pretty time consuming if you're inheriting a large hierarchy, but if it's for a not-so-big class it should be very reasonable and being quite natural for the user.
I have a trick, not a clean solution.
class ConstChild : private Property
{
operator const Property () { return *this; }
};
then
ConstChild cc;
cc.set(10); // ERROR
cc().get();
I am trying to use CRTP to register all live (created but not yet destroyed) instances of some class. This works for me well:
template <typename T>
class Registrable {
public:
void _register(T* p) { instances_.insert(p); }
void _unregister(T* p) { instances_.erase(instances_.find(p)); }
static const std::set<T*> & instances() { return instances_; }
private:
static std::set<T*> instances_;
};
template <typename T>
std::set<T*> Registrable<T>::instances_;
class Class : private Registrable<Class> {
public:
using Registrable<Class>::instances;
Class() { _register(this); }
Class(const Class &) { _register(this); }
Class(Class &&) { _register(this); }
~Class() { _unregister(this); }
void function() { }
};
int main() {
Class c;
auto upc = std::make_unique<Class>(c);
std::vector<Class> vc(5);
for (auto i : Class::instances())
i->function();
}
EDITED:
Better would be not to care about registering and unregistering of instances in derived classes. Solution according to #Jean-BaptisteYunès and #Aconcagua:
template <typename T>
class Registrable {
public:
static const std::set<T*> & instances() { return instances_; }
protected:
Registrable() { instances_.insert(static_cast<T*>(this)); }
Registrable(const Registrable &) : Registrable() { }
Registrable(Registrable &&) : Registrable() { }
~Registrable() { instances_.erase(instances_.find(static_cast<T*>(this))); }
private:
static std::set<T*> instances_;
};
...
class Class : public Registrable<Class> { ... }
However, I am also not sure whether this type of casting is safe. Especially, if Class would additionally derive from another class via multiple inheritance.
The answer of #amc176 claims, that I can assume that the cast will be successful, but I would prefer to be sure. According to #Aconcagua's comment, I can be sure, just it's not in the answer.
static_cast makes no runtime checks to ensure the cast is completely safe. Anyway, as you know the type T will be a derived class of Registrable<T>, you can assume the cast will be successful.
In fact, in cppreference it's mentioned that this cast is typically used when applying CRTP (referred as static polymorphism in the link).
I am trying to solve a programming problem that consists of an object (call it Diagram), that contains several parameters. Each parameter (the Parameter class) can be one of several types: int, double, complex, string - to name a few.
So my first instinct was to define my Diagram class as having a vector of template parameters, which would look like this.
class Diagram
{
private:
std::vector<Parameter<T> > v;
};
This doesn't compile, and I understand why. So, based on the recommendations on this page How to declare data members that are objects of any type in a class, I modified my code to look like:
class ParameterBase
{
public:
virtual void setValue() = 0;
virtual ~ParameterBase() { }
};
template <typename T>
class Parameter : public ParameterBase
{
public:
void setValue() // I want this to be
// void setValue(const T & val)
{
// I want this to be
// value = val;
}
private:
T value;
};
class Diagram
{
public:
std::vector<ParameterBase *> v;
int type;
};
I'm having trouble figuring out how to call the setValue function with an appropriate templated parameter. It is not possible to have a templated parameter in the ParameterBase abstract base class. Any help is greatly appreciated.
P.S. I don't have the flexibility to use boost::any.
You got very close. I added a few bits because they're handy
class ParameterBase
{
public:
virtual ~ParameterBase() {}
template<class T> const T& get() const; //to be implimented after Parameter
template<class T, class U> void setValue(const U& rhs); //to be implimented after Parameter
};
template <typename T>
class Parameter : public ParameterBase
{
public:
Parameter(const T& rhs) :value(rhs) {}
const T& get() const {return value;}
void setValue(const T& rhs) {value=rhs;}
private:
T value;
};
//Here's the trick: dynamic_cast rather than virtual
template<class T> const T& ParameterBase::get() const
{ return dynamic_cast<const Parameter<T>&>(*this).get(); }
template<class T, class U> void ParameterBase::setValue(const U& rhs)
{ return dynamic_cast<Parameter<T>&>(*this).setValue(rhs); }
class Diagram
{
public:
std::vector<ParameterBase*> v;
int type;
};
Diagram can then do stuff like these:
Parameter<std::string> p1("Hello");
v.push_back(&p1);
std::cout << v[0]->get<std::string>(); //read the string
v[0]->set<std::string>("BANANA"); //set the string to something else
v[0]->get<int>(); //throws a std::bad_cast exception
It looks like your intent is to store resource-owning pointers in the vector. If so, be careful to make Diagram have the correct destructor, and make it non-copy-constructable, and non-copy-assignable.
The bellow implementation uses a few C++11 features but you will be
able to pick them apart.
#include <vector>
#include <memory>
class Parameter
{
private:
class ParameterBase {
public:
virtual ~ParameterBase() {}
virtual ParameterBase* copy() = 0;
virtual void foo() = 0;
};
template <typename T>
class ParameterModel : public ParameterBase {
public:
// take by value so we simply move twice, if movable
ParameterModel(const T& t) : t(t) {}
ParameterModel(T&& t) : t(t) {}
void foo() { t.foo(); }
ParameterModel* copy() { return new ParameterModel(*this); }
private:
T t;
};
public:
template <typename T>
Parameter(T&& t)
: pp(new ParameterModel< typename std::remove_reference<T>::type >(std::forward<T>(t))) {}
// Movable and Copyable only
Parameter(Parameter&&) = default;
Parameter& operator=(Parameter&&) = default;
Parameter(const Parameter& other) : pp(other.pp->copy()) {};
Parameter operator=(const Parameter& other) {
pp.reset(other.pp->copy());
return *this;
};
// members
void foo() { pp->foo(); }
private:
std::unique_ptr<ParameterBase> pp;
};
class Diagram
{
public:
std::vector<Parameter> v;
int type;
};
struct X {
void foo() {}
};
struct Y {
void foo() {}
};
int main()
{
Diagram d;
d.v.emplace_back(X()); // int
// parameters are copyable and can be reassigned even with different
// impls
Parameter p = d.v.back();
Parameter other((Y()));
other = p;
return 0;
}
What does this code do? It hides the fact that we use inheritance to
implement parameters from our users. All they should need to know is
that we require a member function called foo. These requirements are
expressed in our ParameterBase. You need to identify these
requirements and add the to ParameterBase. This is basically a more
restrictive boost::any.
It is also quite close to what is described in Sean Parent's value semantics talk.
I've tried to use c++ properties and now I'm stuck with this:
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a {
public:
getonly<b, int> id;
};
What I want is something like this, where getonly is parametrized by only the typename (int), and not the class (b):
class b : public a {
public:
getonly<int> id;
};
Is this possible? Can anyone help me?
It appears that you want a data member that can be read by any code, but that can only be changed by the containing class.
The attempt at providing friend-ship via template would not have compiled prior to C++11. It means that this code can not be easily modified to work with a C++03 compiler (with C++03 one could express the access restriction on modification via e.g. an owner credential argument to a setter). However, that concern becomes less significant every day.
Here's your code modified to compile, and with the inheritance changed from public to private (it doesn't make much sense to say that b "is-an" a):
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<class s, typename t>
class getonly {
protected:
friend s;
t value_;
public:
auto get() const -> t const& { return value_; }
operator t const& () const { return value_; }
getonly( t v ): value_( v ) {}
};
};
class b : private a {
public:
getonly<b, int> id;
void set_id( int x ) { id.value_ = 2*x; }
b(): id( 42 ) {}
};
#include <iostream>
auto main() -> int
{
using namespace std;
b obj;
cout << obj.id << endl;
obj.set_id( 333 );
cout << obj.id << endl;
}
So first off, this can be done with CRTP
template<typename s>
class a {
protected:
// wikipedia https://en.wikipedia.org/wiki/Property_(programming)#C.2B.2B
template<typename t>
class getonly {
protected:
friend s;
t value;
t set(); // operator =...
public:
t get(); // t operator...
};
};
class b : public a<b> {
public:
getonly<int> id;
};
But since you mentioned inheritance, are you aware that friend declarations are not inherited? If that is your goal, then there is a more elegant solution - do not use the property as a base class but as traits:
template<typename T, typename F>
class property_impl
{
friend F;
private:
T value_;
protected:
void set(T value)
{
value_ = value;
}
public:
T get()
{
return value_;
}
};
template<typename F>
class property_traits
{
template<typename T> using property = property_impl < T, F > ;
};
class foo : public property_traits < foo >
{
public:
property<int> id_;
};
class bar : public foo, public property_traits < bar >
{
public:
property<int> another_id_;
void doStuff(foo f)
{
auto value = f.id_.get();
// f.id_.set(5); <-- fails since friend is not inherited
}
};
int main(int argc, char** argv)
{
foo f;
auto value = f.id_.get();
bar b;
auto another_value = b.another_id_.get();
b.doStuff(f);
return 0;
}
This will give you the ability to inherit and specialize on each class that needs a property while retianing the fact, that only the class type used in specialization is able to modify the value.
Again, maybe you want that, I am not sure.
Following does not work:
std::vector<IRule*> vec;
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
Now how can a make a vector of different rules? I know, I have to use pointers... But what else do I have to do to get this working? How can I change my base structure to get this work?
I use an Interface like the following:
// Interface
template <typename T>
class IRule
{
public:
virtual bool isValid(T value) = 0;
};
And my example class looks like this:
class RuleRangeDouble : public IRule<double>
{
private:
double min;
double max;
public:
bool isValid(double value)
{
....
};
};
The vector needs to be a vector of an actual type, for example std::vector<IRule<double>*>. Irule on its own is not a type, it is a class template. So you would need
std::vector<IRule<double>*> vec;
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
If the template parameter is not part of the interface, you can introduce a common base class. Don't forget to give it a virtual destructor:
class IRule
{
public:
virtual bool isValid(T value) = 0;
virtual ~IRule() {}
};
template <typename T>
class Rule : public IRule
{
.....
};
class RuleRangeDouble : public Rule<double>
{
....
};
Then your original use case sample would work:
std::vector<IRule*> vec; // IRule really is a type now
RuleRangeDouble *rule = new RuleRangeDouble(0, 100);
vec.push_back(rule);
You can implement something like getBestValidValue()in several ways. One is to define a special general (but non-template) return type to be used for getBestValidValue() and also as argument type for isValid(value) (juanchopanza's answer was faulty here):
class ValueType
{
enum { is_int, is_double } my_type; // add more if you want
union { my_int; my_double; }; // union only works for simple types
public:
// implicit construction from allowed types
ValueType(int x) : my_type(is_int), my_int(x) {}
ValueType(double x) : my_type(is_double), my_double(x) {}
// use SFINAE for is<type>() function
template<typename T>
typename std::enable_if<std::is_same<T,int>::value,bool>::type
is() const { return my_type==is_int; }
template<typename T>
typename std::enable_if<std::is_same<T,double>::value,bool>::type
is() const { return my_type==is_double; }
// implicit type conversion to allowed types
// note: does not assert(is<T>())
operator int() { return my_int; }
operator double() { return my_double; }
};
class IRule
{
public:
virtual bool isValid(ValueType const&) const = 0; // fixed bug in juanchopanza's answer
virtual ValueType getBestValidValue() const = 0; // return any type of value
virtual ~IRule() {}
};
template<typename T>
class Rule : public IRule
{
protected:
virtual bool valid(T) const = 0;
virtual T bestValidValue() const = 0;
public:
bool isValid(ValueType const&value) const
{
return value.is<T>()
&& valid(value); // implicit type conversion to T
}
ValueType getBestValidValue() const
{
return bestValidValue(); // implicit construction of ValueType
}
....
}