A property is a public data member of a class, which can be accessed by client code. And the owning object receives a notification (in the form of get/set notification callback) whenever the client code reads or modifies the property.
Some languages (like C#) have built-in properties.
I want to create a property for C++ that will be RAM-efficient.
The most obvious way to make a property is something like this:
class Super;
struct Prop {
Prop( Super * super ) : m_super(*super), m_a(0) {}
int operator=( int a );
operator int() const;
int m_a;
Super & m_super;
};
struct Super {
Super() : one(this), two(this) {}
void onSet() { printf("set"); }
void onGet() { printf("get"); }
Prop one;
Prop two;
};
int Prop::operator=( int a ) { m_super.onSet(); m_a = a; return a; }
Prop::operator int() const { m_super.onGet(); return m_a; }
Trouble is - every property has to keep a pointer to the outer class which I consider costly.
I want to know if there is a more RAM-efficient way to do this?
For example, if all Super-classes are generated, is it allowed by the Standard to get a pointer to the outer class from this pointer of the property?
Something like this:
struct Prop {
Prop( uint8_t offset ) : m_offset(offset), m_a(0) {}
int operator=( int a );
operator int() const;
int m_a;
const uint8_t m_offset;
};
int Prop::operator=( int a ) {
Super * super = (Super *)( ((char *)this) + m_offset);
super->onSet(); m_a = a; return a;
}
struct Super {
// assuming exact order of properties
Super() : one(0), two(sizeof(Prop)) {}
void onSet() { printf("set"); }
void onGet() { printf("get"); }
Prop one;
Prop two;
};
Since this offset is a constant expression it (theoretically) can be kept in ROM (or at least it can be smaller than sizeof(pointer)).
Or maybe there is another way?
c++ has properties as language extension
Look no further, msvc has support.
clang compiler also supports this syntax. Im not sure about gcc.
Storing offset can be also be done
Just, in the constructor calculate the offset from this, ala. :
Prop( Super& super ) {
uint8_t offset = this - std::addressof(super );//somewhat unmaintable - but may save some bytes
}
then when used, calculate back using this
Please note the space saving may be less than it seems due to alignment and padding.
I obviously don't know the context of your code, so this may be inconceivable in your specific implementation, but you could do something like
class Prop(){
Prop() : m_a(0){};
int operator=(int a){m_a = a;};
int m_a;
}
class Super(){
public:
int set_prop(int index, int value){
m_props[index] = value;
onSet();
return value;
}
private:
void onSet(){};
std::vector<Prop> m_props;
}
Obviously you need to initialize the vector and handle error cases etc but the logic is there - if you only access the props through the super.
That leaves you with purely the size of the sequence of structs with no pointers back to the super.
Related
I have code like this:
class Human
{
protected:
int age;
std::string sex;
public:
virtual void speak() = 0;
};
class Child:public Human
{
public:
void speak(){std::cout << "I am Child\n";}
};
class Man:public Human
{
public:
void speak(){std::cout << "I am Man\n";}
};
class Woman:public Human
{
public:
void speak(){std::cout << "I am Woman\n";}
};
(don't know, std::shared_ptr<Human> maybe?) operator*(std::shared_ptr<Child> &b, int x)
{
b->setAge(b->getAge()+x);
if(b->getAge()>18 && b->getSex()=="Man")
{
return (i want b to become std::shared_ptr<Man>)
}
if(b->getAge()>18 && b->getSex()=="Woman")
{
return (here I want b to become std::shared_ptr<Woman>);
}
return;
}
int main(){
auto x = std::make_shared<Child>;
x*19;
}
I know it seems odd, but it's the simplest case i can think of, without having to write down all code i'm struggling with rn. Could someone explain, what type should overload be and how to change shared_ptr type, knowing they derive from same parent?
Objects cannot change type. A Child object will always be a Child object. What you can do is create a new object with the properties you want and return that:
std::shared_ptr<Human> operator*(std::shared_ptr<Human> b, int x)
{
b->setAge(b->getAge()+x);
if(b->getAge()>18 && b->getSex()=="Man") {
return std::make_shared<Man>(b->getAge());
} else if(b->getAge()>18 && b->getSex()=="Woman") {
return std::make_shared<Woman>(b->getAge());
} else {
return b;
}
}
int main(){
std::shared_ptr<Human> x = std::make_shared<Child>;
x = x*19;
}
This doesn't seem like a good design though. A Human's status as a child or adult would be better represented as an attribute of the object or by a function that checks if age is greater than 18.
You cannot make the type T<Derived> inherit from T<Base> because C++ templates do not support covariance. To do so would be unsafe for certain types, such as mutable references to containers. (Imagine taking a reference to std::vector<Cat> as std::vector<Animal>& and pushing back a dog!)
(I would make this answer a comment, but I don't have comment abilities.)
Update:
You can write a non-template wrapper that handles heap data:
class Wrapper
{
public:
Wrapper(Base* b) : raw(b) {}
~Wrapper() { delete raw; }
Base& get() { return *base; }
private:
Base* raw;
}
Of course, in your example, you use std::shared_ptr and not std::unique_ptr. You would have to handle reference counting instead of simply deleting the data in the destructor, but the technique of keeping an internal raw pointer still stands.
Update 2:
The above code could be used as is to provide a level of indirection, such that all classes that inherit from the base class may be held in the same type, without writing your own reference counter:
std::shared_ptr<Wrapper>
This solution may be seen as similar to doing std::shared_ptr<Base*>, except that the latter solution would leak memory.
I'm using a library (libtcod) that has an A* pathfinding algorithm. My class inherits the callback base class, and I implement the required callback function. Here is my generic example:
class MyClass : public ITCODPathCallback
{
...
public: // The callback function
float getWalkCost(int xFrom, int yFrom, int xTo, int yTo, void *userData ) const
{
return this->doSomeMath();
};
float doSomeMath() { // non-const stuff }
};
I found a number of examples using const_cast and static_cast, but they seemed to be going the other way, making a non-const function be able to return a const function result. How can I do it in this example?
getWalkCost() is defined by my library that I cannot change, but I want to be able to do non-const things in it.
The best solution depends on why you want to do non-const stuff. For example, if you have a cache of results that you want to use to improve performance, then you can make the cache be mutable, since that preserves the logical constness:
class MyClass : public ITCODPathCallback
{
...
public: // The callback function
float getWalkCost(int xFrom, int yFrom, int xTo, int yTo, void *userData ) const
{
return this->doSomeMath();
};
float doSomeMath() const { // ok to modify cache here }
mutable std::map<int,int> cache;
};
Or perhaps you want to record some statistics about how many times the getWalkCost was called and what the maximum x value was, then passing a reference to the statistics may be best:
class MyClass : public ITCODPathCallback
{
...
public:
struct WalkStatistics {
int number_of_calls;
int max_x_value;
WalkStatistics() : number_of_calls(0), max_x_value(0) { }
};
MyClass(WalkStatistics &walk_statistics)
: walk_statistics(walk_statistics)
{
}
// The callback function
float getWalkCost(int xFrom, int yFrom, int xTo, int yTo, void *userData ) const
{
return this->doSomeMath();
};
float doSomeMath() const { // ok to modify walk_statistics members here }
WalkStatistics &walk_statistics;
};
You can hack it this way:
return const_cast<MyClass*>(this)->doSomeMath();
Of course this won't be considered good design by most people, but hey. If you prefer you can instead make doSomeMath() const, and mark the data members it modifies as mutable.
How to Define or Implement C# Property in ISO C++ ?
Assume following C# code :
int _id;
int ID
{
get { return _id; }
set { _id = value; }
}
I know C# convert the get and set lines to getXXX and setXXX methods in compile time. in C++ , programmers usually define these two function manually like :
int _id;
int getID() { return _id; }
void setID(int newID) { _id = newID; }
but, I want to have the C# syntax or a stuff like it in order to have a simple usability.
In C#, we can use properties like :
ID = 10; // calling set function
int CurrentID = ID; // calling get function
In C++, we can use our function like :
setID(10); // calling set function
int CurrentID = getID(); // calling get function
Now tell me how can I implement the C# properties in ISO C++.
thanks.
As Alexandre C. has already stated, it's very awkward and not really worth it, but to give an example of how you might do it.
template <typename TClass, typename TProperty>
class Property
{
private:
void (TClass::*m_fp_set)(TProperty value);
TProperty (TClass::*m_fp_get)();
TClass * m_class;
inline TProperty Get(void)
{
return (m_class->*m_fp_get)();
}
inline void Set(TProperty value)
{
(m_class->*m_fp_set)(value);
}
public:
Property()
{
m_class = NULL;
m_fp_set = NULL;
m_fp_set = NULL;
}
void Init(TClass* p_class, TProperty (TClass::*p_fp_get)(void), void (TClass::*p_fp_set)(TProperty))
{
m_class = p_class;
m_fp_set = p_fp_set;
m_fp_get = p_fp_get;
}
inline operator TProperty(void)
{
return this->Get();
}
inline TProperty operator=(TProperty value)
{
this->Set(value);
}
};
In your class where you wish to use it, you create a new field for the property, and you must call Init to pass your get/set methods to the property. (pref in .ctor).
class MyClass {
private:
int _id;
int getID() { return _id; }
void setID(int newID) { _id = newID; }
public:
Property<MyClass, int> Id;
MyClass() {
Id.Init(this, &MyClass::getID, &MyClass::setID);
}
};
Short answer: you can't.
Long answer: You could try to simulate them via proxy classes, but believe me this is not worth the minor incovenience in having set/get functions.
You'd have basically to define a class which forwards all the behavior of the variable. This is insanely hard to get right, and impossible to be made generic.
Quite simply. I'd argue this even has no overhead compared to making the variable public. However, you can't modify this any further. Unless, of course, you add two more template parameters that are call backs to functions to call when getting and setting.
template<typename TNDataType>
class CProperty
{
public:
typedef TNDataType TDDataType;
private:
TDDataType m_Value;
public:
inline TDDataType& operator=(const TDDataType& Value)
{
m_Value = Value;
return *this;
}
inline operator TDDataType&()
{
return m_Value;
}
};
EDIT: Don't make the call back functions template parameters, just data members that are constant and must be initialized in the constructor for the property. This inherently has greater overhead than simply writing a get and set method your self, because you're making function calls inside of your gets and sets this way. The callbacks will be set at run-time, not compile-time.
For a constructor with multiple arguments...
For example:
class C {
public:
C(int a=1, int b=2){ cout << a << ", " << b << "\n"; }
}
int main(){
C a(10), b = 20;
}
output:
10, 2
20, 2
How do I just assign value to the 2nd parameter? So that I can get "1, 20" without knowing the default values? Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
And how do I implicitly assign all the parameters? If I can't do that, why? For the above example (as I am new to C++), I once thought I would get "10, 20" as output instead.
Or is that that I must always assign value to the argument that precedes before I can use the arguments behind?
Yes. Otherwise, how is the compiler supposed to know which argument should be used for which parameter?
However, there are ways to accomplish this. For example,
struct C {
enum { DefaultA = 1, DefaultB = 2 };
C(int a = DefaultA, int b = DefaultB) { /* ... */ }
};
C object(C::DefaultA, 20);
Or, if you have a lot of parameters with different "defaults:"
struct CParams {
int a, b;
CParams() : a(1), b(2) { }
};
struct C {
C(CParams x) { /* ... */ }
};
CParams params;
params.b = 20;
C object(params);
C++ doesn't support named arguments. You have to specify the first one.
Also, the variable name b from the main function is completely separate from the b in the constructor definition. There's no relationship whatsoever implied by the naming.
I had the same thought (Convienient C++ struct initialisation -- perhaps you find something you like better there) some time ago, but just now, reading your question, I thought of a way to actually accomplish this. But it is quite some extra code, so the question remains if it is actually worth it. I just implemented it very sketchy and I am not proud of my choice of names (I usually don't use _ but it's late). Anyway, this is how you can do it:
#include <iostream>
struct C_members {
int a;
int b;
C_members(int _a, int _b) : a(_a), b(_b) {}
};
class C_init {
public:
virtual C_members get(C_members init) const {
return init;
}
};
class C_a : public C_init {
private:
int a;
public:
C_a(int _a) : a(_a) {}
C_members get(C_members init) const {
init.a = a;
return init;
}
};
class C_b : public C_init {
private:
int b;
public:
C_b(int _b) : b(_b) {}
C_members get(C_members init) const {
init.b = b;
return init;
}
};
class C : private C_members {
private:
static const C_members def;
public:
C(C_init const& ai = C_init(), C_init const& bi = C_init()) : C_members(ai.get(bi.get(def)).a, bi.get(ai.get(def)).b) {
std::cout << a << "," << b << std::endl;
}
};
const C_members C::def(1,2); // default values
// usage:
int main() {
C c1(C_b(77)); // 1,77
C c2(C_a(12)); // 12,2
C c3(C_b(5),C_a(6)); // 6,5
return 0;
}
There is a lot of stuff that can be improved (with templates (for code reduction) and with const refs in the get method), but you get the idea.
As a bonus feature, you almost have the pimpl idiom implemented (very little effort is necessary to extend this to an actual pimpl design).
Usually in OOP, every object instance holds (and represents) a state.
So the best way is to define an accessor functions such as
void setB(int newBvalue);
and also to hold b as a private member.
if "b" is shared among all the instances of the same object, consider to save a static variable.
I have a struct:
struct s
{
UINT_PTR B_ID;
};
s d;
d.B_ID=0x1;
That works fine, but I want d.B_ID to be constant. I tried to use (const) but it didn't work. So after I put a value to d.B_ID, then I want make it a constant.
Any ideas?
EDIT
ok i don't want the whole struct a constant.
when i set timer and use the b.B_ID as an idea for the timer.
in the
switch(wparam)
{
case b.B_ID // error: B_ID must be constant
....
break;
}
so that is why i need it to be a constant
Variable modifiers are fixed at compile time for each variable. You may have to explain the context of what you are trying to do, but perhaps this will suit your needs?
struct s
{
int* const B_ID;
};
int main (void) {
int n = 5;
s d = {&n};
int* value = d.B_ID; // ok
// d.B_ID = &n; // error
return 0;
}
Since you are using C++ I would recommend:
class s {
public:
int* const B_ID;
s (int* id) :
B_ID (id) {
}
};
void main (void) {
int n = 5;
s my_s_variable = s(&n);
int* value = my_s_variable.B_ID; // ok
//my_s_variable.B_ID = &n; // error
return 0;
}
Ramiz Toma: well i need way to do it using the s.B_ID=something
In C/C++ type modifiers (like const) are declared at run time for a given type and cannot be changed at run time. This means that if a variable is declared const it can never be assigned to using the assignment operator. It will only be assigned a value when it is constructed.
This is not a problem however because you can always get around this by proper design.
If you say you need to use assignment, I assume that this is because you create the struct before you know what the value of the variable will be. If this is the case then you simply need to move the struct declaration till after you know the value.
For example
s d; //variable declaration
//calculate B_ID
//...
int* n = 5;
//...
d.B_ID = &n;
This will not work, because if you want b.D_ID to be 'un assignable' it will always be so. You will need to refactor your code similarly to:
//calculate B_ID
//...
int* n = 5;
//...
s d (&n);
//good
struct s
{
s() : B_ID(0){}
UINT_PTR const B_ID;
};
int main(){
s d;
d.B_ID=0x1; // error
}
EDIT: Sorry, here is the updated code snippet in C++
struct s
{
s(UINT_PTR const &val) : B_ID(val){}
UINT_PTR const B_ID;
};
int main(){
s d(1);
d.B_ID=0x1; // error
}
In C++ language the case label must be built from an Integral Constant Expression (ICE). ICE is what the compiler implies under the term "constant" in your error message. A non-static member of a class cannot be used in an ICE. It is not possible to do literally what you are trying to do. I.e. it is not possible to use a struct member in a case label.
Forget about switch/case in this context. Use ordinary if branching instead of switch statement.
You can't do that - ie. it is not possible to selectively make a single member of a struct const. One option is to 'constify' the entire struct:
s d;
d.B_ID=0x1;
const s cs = s; // when using this B_ID won't be modifiable - but nor would any other members
Or you could set it at construction:
struct s
{
s(UINT_PTR const p): B_ID(p) {}
UINT_PTR const B_ID;
};
s d(0xabcdef);
Another way would be a getter and a one time setter
class s
{
private:
bool m_initialized;
UINT_PTR m_value;
public:
s() : m_initialized(false), m_value(NULL) {}
s(UINT_PTR value) : m_initialized(true), m_value(value) {}
//no need for copy / assignment operators - the default works
inline UINT_PTR GetValue() const { return m_value; } //getter
bool SetValue(UINT_PTR value) //works only one time
{
if (m_initialized)
{
m_value = value;
m_initialized=true;
return true;
}
else
{
return false;
}
}
inline bool IsInitialized() const { return m_initialized; }
};