I am referring to one of the exercises mentioned in the book "thinking in c++.
Below code snippet throws an error for the call h.play, which i understand, because
the member i is private. But I was expecting the same error for the call me.play. If i comment the call h.play the code compiles fine. Why there is no error for the call me.play ?
class Buddy {};
template<class T> class My {
int i;
public:
void play(My<Buddy>& s) {
s.i = 3;
}
};
int main() {
My<int> h;
My<Buddy> me, bud;
h.play(bud);
me.play(bud);
}
Thankyou.
[Edit] Is there a way to see what code the compiler has generated for
My<int> h and
My<Buddy> me
? (anything similar to -E compiler flag) ?
Members are always "public" to instances of another object with the same type.
Meaning a My<Buddy> instance (such as me) can access private members of another My<Buddy> instance (such as bud).
Keep in mind that My<int> is a completely different type than My<Buddy>, and so it cannot access those members.
Because the play method is defined as taking a reference to My<Buddy> rather than a My<T>, the effective class is the same type when called on another instance of My<Buddy>. Therefore private members are accessible.
Unlike in languages that just pretend to have strong static type system and generics (looking at you Java), C++ allows you to disambiguate statically parametric types (template types) based on the parameters (the parameters being usually types) the types are templated on.
Note: You can also use a derived (dynamically / late bound) type as a parameter for a statically parametrized type, but it's not relevant in this scenario.
In other words, in C++:
typeid(me) == typeid(bud) will be TRUE
typeid(h) == typeid(me) will be FALSE
even though the type "My" is the same.
You can access the private data-members from the same type as though they were public, but as you can see, the second comparison is false because the operands are not of the same type, therefore you violate the access restrictions of the type.
Also, I don't think there is any way to take a look at the compiler-generated code. (As far as I know.)
Related
I want to detect during compile time (static assertion) whether a class meets both the following conditions:
Has an implicit default constructor (i.e., no user-defined default constructor).
Has at least one data member which is a pod (i.e., a member whose default initialization is to assume whatever random bytes was in its memory address).
[I hope I used the term pod correctly here]
The idea is to avoid working with objects with uninitialized members. I know there are different methods to do this during coding, but I also want a mechanism to detect this during compilation.
I tried using different std/boost functions, such as is_trivially_constructible, is_pod, but none of these provide the exact terms I need.
For example, let's say I have the following classes:
struct A
{
int a;
}
struct B
{
int* b;
}
struct C
{
bool c;
std::string c_str_;
}
struct D
{
D();
float d;
}
struct E
{
std::string e;
}
Assuming the function I need is called "has_primitive_and_implicit_ctor", I would like the output for each call to be as in the comments:
has_primitive_and_implicit_ctor<A>(); //true - A has at least one pod type member (int)
has_primitive_and_implicit_ctor<B>(); //true - A has at least one pod type member (pointer)
has_primitive_and_implicit_ctor<C>(); //true - A has at least one pod type member (bool), even though there is one non-pod member
has_primitive_and_implicit_ctor<D>(); //false - has a pod member(float), but a user defined ctor
has_primitive_and_implicit_ctor<E>(); //false - doesn't have a default ctor but has no pod members
Firstly, it seems to me like a broken design to expect from the user of a class to care about its member initialisation. You should make sure in the class itself that all its members are initialised, not somewhere else where it is used.
What you are looking for does not exist, and if it would, it would not even help you. The existence of an explicit constructor does not guarantee that a data member is initialised. On the other hand, with C++11 it is even possible to initialise data members without explicitly writing a constructor (using the brace syntax in the class declaration). Also you just seem to care about uninitialised POD members, but what about uninitialised non-POD members?
That said, compiler can generate warnings about uninitialised values, but often you have to enable this warning (e.g. -Wuninitialized option for gcc). Most compilers allow to force treating warnings as an error. In combination this can give you the desired effect even without specifically writing code to test for it, and it would also work for any uninitialised values, not only those in classes. Maybe this is the solution you are looking for.
Look at this snippet:
struct A {
void fn();
};
struct B: A {
};
void f() {
auto x = &B::fn;
}
Here, x gets a type of void (A::*)(), despite the fact that I've written &B::fn.
If I added fn into B, then type of x would be void (B::*)().
So, type of &B::fn changes whether B has a fn, or not.
What is the rationale behind this behavior? I find it surprising.
Why does this matter? Suppose this: programmer X creates A and B, like in my example. Programmer Y uses &B::fn, and uses the class-part of its type for something (like a parameter to a template, whatever). Then programmer X realizes, that he needs some extra functionality in fn, so he overrides it. Now, programmer Y's code can be broken, as type of &B::fn have changed.
This was the subject of CWG issue 203 and EWG issue 89. Initially, the rationale was to allow as much code as possible to be valid:
Notes from 04/00 meeting:
The rationale for the current treatment is to permit the widest possible use to be made of a given address-of-member expression. Since a pointer-to-base-member can be implicitly converted to a pointer-to-derived-member, making the type of the expression a pointer-to-base-member allows the result to initialize or be assigned to either a pointer-to-base-member or a pointer-to-derived-member. Accepting this proposal would allow only the latter use.
Later, after the problems caused by it had become more obvious, it was too late to fix:
Additional note, April, 2015:
EWG has determined that the utility of such a change is outweighed by the fact that it would break code. See EWG issue 89.
I think that the main idea comes from that usual "B is A" class inheritance definition. You can rephrase it for member functions like "functions of A are functions of B", however statement with flipped A and B position is correct only for some items, that is "only some functions of B are functions of A". So B::fn fits into this category of functions of B that are functions of A. By writing function fn in class B we at the same time move B::fn out of this category into category of functions of B that are not functions of A.
This allows one to check whether class overrides some method of base class:
const bool fn_is_overriden{::std::is_same<decltype(&A::fn), decltype(&B::fn)>::value};
In most ways, a member function is like a free function with an implicit object argument. So this code:
struct A {
void fn();
};
is very similar to:
struct A {};
void A_fn(A* this_);
For example, overload resolution between member functions and free functions is defined in this way, so that all of the functions can be ranked on the same footing.
When you inherit a member (variable or function), you inherit that function as it is. Inheritance doesn't define new functions or variables. All it does is create names in the derived class that refer to the existing members of the base class.
You've still got A_fn(A* this), just that it is accessible from B's scope. The access rules for inheritance apply to the inherited names only, they don't change any properties of the member.
Below C++11 code won't compile (should work to my first impression) under g++ 4.9.2:
class A{};
class B : public A{};
void func(shared_ptr<B>){}
TEST(testFunc, testFunc_conv){
std::function<void(shared_ptr<A>)> afunc;
afunc = func;
}
The error messages indicate it doesn't accept the conversion from shared_ptr<B> to shared_ptr<A> though those B can be converted to A.
Why doesn't this work? Is it possible to work around this limitation?
EDIT
I consider the implications carefully and understand the reason - A can't be converted to B indeed, so it's not allowed for the sake of type safety.
The background of this code is to implement some generic interface with variadic parameters, so other part of the world can register a callable that taking derivatives of an empty base type. The callable would be called later (kind of deferred call):
//action would be stored for deferred call
// when action is actually called, it will use the real type
template<class ObjType>
registerInterface(function<void(Base*)> action, ObjType* obj){
function<void()> callable = [=]{ action(obj);}
//callable action would be stored for deferred call
}
void interfaceImpl(Derived* d){
d->realOperation();
}
//do registration - need to do the conversion each time for each interface implementation!
Derived d;
registerInterface(interfaceImpl, &d);
It would be annoying for each interfaceImpl to declare as taking the base type and do the downcasting brutely.
My solution is to remove the function from interface and set a implicit callable template argument for interfaceImpl to specify. Appreciate if there're better solutions.
If you want polymorphism, the declaration should include the parent class so you are able to pass its a children into it.
You are using a specific child in the definition, then trying to use the function with the base one. Obviously this would not work.
Either inherit from B or change the declaration to use the class A.
Note:
I am pretty sure you can do what you are trying to achieve in C++. However, the question you should ask yourself is: "Just because I can, should I really do it?" For example, just because you can abuse pointers to retrieve a private member of a class does not mean you should do it, and making an accessor will nearly always be the better choice.
Remember, code is being much more often read and reviewed than written. I would much rather see a straightforward code, than reading a pice of code including special constructs of the language just to make it work.
shared_ptr<B> is convertible to shared_ptr<A>. The buck stops here. Types below are not convertible:
shared_ptr<B>* to shared_ptr<A>*
void(*)(shared_ptr<B>) to void(*)(shared_ptr<A>)
function<void(shared_ptr<B>)> to function<void(shared_ptr<A>)>
This is for a good reason. What happens in the next fragment?
func (new A); // should not compile
afunc = func; // imagine this is allowed
afunc(new A); // now what?
Some of the conversions above but in the opposite direction do make sense, but C++ doesn't allow them for a number of historical and other reasons.
Fortunately you don't need any of this. You can do
template<class ObjType>
registerInterface(function action, ObjType* obj)
Or, better
registerInterface(std::function<void()> func) ...
And then call
register_interface(std::bind(funcA,objA));
register_interface(std::bind(funcB,objB));
You write "those 2 types are convertible". They are not.
Since B is a subtype of A, B can be assumed to hold additional members. Therefore it is not allowed to do what you are trying. You are saying specifically that func needs a ptr to B to operate on.
Then you create a function pointer that clearly states you will send something of type A. This can not work, because as stated B being the derived class may contain more members than A, members upon func may depend (since it specifies it explicitly as the argument type).
The other way around is polymorphically ok though. You could pass type B where type A is expected, because A being the base type, this would make it certain that B has the same members, thus it is safe to pass it (since it is of type A).
I'll start with some code:
class myNonPODClass
{
public:
virtual ~myNonPODClass() {}
class
{
public:
myNonPODClass* GetContainer()
{
return (myNonPODClass*)((int8_t*)(this) - offsetof(myNonPODClass, member));
}
} member;
};
Obviously, this is a contrived example. The code compiles fine, but I'm worried about the "Offset of on non-POD type 'myNonPODClass'". Is there a better way to do essentially the same thing WITHOUT having to pass the myNonPODClass pointer into the nested anonymous classes constructor (or similar)? "member" must be ready to go without any initialization. Is it possible? Thanks!
In case you're wondering what on Earth I could want this for, my PROPERTY macro and a commented out example on pastebin (yes, it's awesome ^^ ): http://pastebin.com/xnknf39m
This code does not work, per the C++ specification, for several reasons:
offsetof requires a POD type (in C++11, it requires a standard-layout type). Your type is not, and therefore calling it results in undefined behavior.
The conversion to int8_t* and then to another type is undefined behavior per the C++ specification. You would need to use a char*, which has certain relaxed casting rules.
Given the following template:
template <typename T>
class wrapper : public T {};
What visible differences in interface or behaviour are there between an object of type Foo and an object of type wrapper<Foo>?
I'm already aware of one:
wrapper<Foo> only has a nullary constructor, copy constructor and assignment operator (and it only has those if those operations are valid on Foo). This difference may be mitigated by having a set of templated constructors in wrapper<T> that pass values through to the T constructor.
But I'm not sure what other detectable differences there might be, or if there are ways of hiding them.
(Edit) Concrete Example
Some people seem to be asking for some context for this question, so here's a (somewhat simplified) explanation of my situation.
I frequently write code which has values which can be tuned to adjust the precise performance and operation of the system. I would like to have an easy (low code overhead) way of exposing such values through a config file or the user interface. I am currently writing a library to allow me to do this. The intended design allows usage something like this:
class ComplexDataProcessor {
hotvar<int> epochs;
hotvar<double> learning_rate;
public:
ComplexDataProcessor():
epochs("Epochs", 50),
learning_rate("LearningRate", 0.01)
{}
void process_some_data(const Data& data) {
int n = *epochs;
double alpha = *learning_rate;
for (int i = 0; i < n; ++i) {
// learn some things from the data, with learning rate alpha
}
}
};
void two_learners(const DataSource& source) {
hotobject<ComplexDataProcessor> a("FastLearner");
hotobject<ComplexDataProcessor> b("SlowLearner");
while (source.has_data()) {
a.process_some_data(source.row());
b.process_some_data(source.row());
source.next_row();
}
}
When run, this would set up or read the following configuration values:
FastLearner.Epochs
FastLearner.LearningRate
SlowLearner.Epochs
SlowLearner.LearningRate
This is made up code (as it happens my use case isn't even machine learning), but it shows a couple of important aspects of the design. Tweakable values are all named, and may be organised into a hierarchy. Values may be grouped by a couple of methods, but in the above example I just show one method: Wrapping an object in a hotobject<T> class. In practice, the hotobject<T> wrapper has a fairly simple job -- it has to push the object/group name onto a thread-local context stack, then allow the T object to be constructed (at which point the hotvar<T> values are constructed and check the context stack to see what group they should be in), then pop the context stack.
This is done as follows:
struct hotobject_stack_helper {
hotobject_stack_helper(const char* name) {
// push onto the thread-local context stack
}
};
template <typename T>
struct hotobject : private hotobject_stack_helper, public T {
hotobject(const char* name):
hotobject_stack_helper(name) {
// pop from the context stack
}
};
As far as I can tell, construction order in this scenario is quite well-defined:
hotobject_stack_helper is constructed (pushing the name onto the context stack)
T is constructed -- including constructing each of T's members (the hotvars)
The body of the hotobject<T> constructor is run, which pops the context stack.
So, I have working code to do this. There is however a question remaining, which is: What problems might I cause for myself further down the line by using this structure. That question largely reduces to the question that I'm actually asking: How will hotobject behave differently from T itself?
Strange question, since you should be asking questions about your specific usage ("what do I want to do, and how does this help me or hurt me"), but I guess in general:
wrapper<T> is not a T, so:
It can't be constructed like a T. (As you note.)
It can't be converted like a T.
It loses access to privates T has access to.
And I'm sure there are more, but the first two cover quite a bit.
Suppose you have:
class Base {};
class Derived : Base {};
Now you can say:
Base *basePtr = new Derived;
However, you cannot say:
wrapper<Base> *basePtr = new wrapper<Derived>();
That is, even though their type parameters may have an inheritance relationship, two types produced by specialising a template do not have any inheritance relationship.
A reference to an object is convertible (given access) to a reference to a base class subobject. There is syntactic sugar to invoke implicit conversions allowing you to treat the object as an instance of the base, but that's really what's going on. No more, no less.
So, the difference is not hard to detect at all. They are (almost) completely different things. The difference between an "is-a" relationship and a "has-a" relationship is specifying a member name.
As for hiding the base class, I think you inadvertently answered your own question. Use private inheritance by specifying private (or omitting public for a class), and those conversions won't happen outside the class itself, and no other class will be able to tell that a base even exists.
If your inherited class has its own member variables (or at least one), then
sizeof(InheritedClass) > sizeof(BaseClass)