Code:
class CFoo
{
int a;
public:
CFoo():a(1){}
~CFoo(){}
getNum(){return a;}
};
void tfunc(void* data)
{
CFoo* foo = static_cast<CFoo*>(data);
std::cout << "Number: " << foo->getNum();
delete foo;
}
int main()
{
CFoo* foo = new CFoo;
void* dt = static_cast<void*>(foo);
tfunc(dt); // or tfunc(static_cast<void*>(food));
return 0;
}
When converting to a void pointer, isn't the value going to be discarded, if yes, how can foo->getNum() be valid?
When converting to a void pointer, isn't the value going to be discarded.
The value that is converted by your statement is the pointer, not the object to which the pointer points.
void* dt = static_cast<void*>(foo);
The value of the variable foo is the address of some CFoo object. The statement defines a new variable, dt, with the same value (i.e., foo and dt both point to the same address), but the compiler won't let you dereference *dt---it will not allow you to fetch a void object from that address---because the void type has no values.
When your program calls tfunc, the formal argument data also gets a copy of the same value (i.e., it points to the same address), and finally so does the local variable foo inside tfunc.
The declared type of the local foo inside tfunc is pointer to CFoo, so the compiler will allow you to dereference that; And, it makes sense because you know that foo actually does point to a legitimate CFoo object.
Related
I'm not sure to understand why I can modify an object from a const method, look:
#include <iostream>
struct Foo {
int a = 0;
void change() {
a = 3;
}
};
struct Test {
Foo* f;
Test(): f{new Foo} {}
void test() const {
f->change();
}
};
int main()
{
Test t;
std::cout << "before: " << t.f->a << "\n";
t.test();
std::cout << "after: " << t.f->a << "\n";
}
Not only it compiles but it prints:
0
3
So I was able to modify the logical state of an object from a const method. Is that because I used a pointer?
The const applies to the pointer itself, f, not to what this pointer is pointing to. The type of f inside your const-qualified member function, Test::test(), is Foo* const (i.e., const pointer to Foo), not const Foo* (i.e., pointer to const Foo). That's why you can modify what the pointer is pointing to in spite of the const qualification of the member function.
Note that the following sample member function, Test::test2(), does fail to compile since it is const-qualified and tries to modify the pointer data member, f:
void Test::test2() const {
f = nullptr; // <-- error
}
No, you did not modify the logical state of an object:
f->change();
f, the object's class member, is as it's always been, here. Its value hasn't changed. It's not pointing to some other object now. It's still pointing to the same object it's always been pointing to.
What you did modify is the object to which f points to. Which is a different object.
Yes, you modified the logical state of the object. That's allowed, because const prohibits modifying the physical state.
The object t has one data member, f, whose type is "pointer to Foo". When the t object is created, it's f member points at an object of type Foo. After the call t.test() the f member still holds the same address, so it points at the same object of type Foo as it did before.
If test() had tried to change the value stored in f (i.e., the pointer) the const would have prevented it.
void Test::test() const { f = new Foo; } // error: `f` is const in this context
Alright, I think the title is sufficiently descriptive (yet confusing, sorry).
I'm reading this library: Timer1.
In the header file there is a public member pointer to a function as follows:
class TimerOne
{
public:
void (*isrCallback)(); // C-style ptr to `void(void)` function
};
There exists an instantiated object of the TimerOne class, called "Timer1".
Timer1 calls the function as follows:
Timer1.isrCallback();
How is this correct? I am familiar with calling functions via function pointers by using the dereference operator.
Ex:
(*myFunc)();
So I would have expected the above call via the object to be something more like:
(*Timer1.isrCallback)();
So, what are the acceptable options for calling functions via function pointers, as both stand-alone function pointers and members of an object?
See also:
[very useful!] Typedef function pointer?
Summary of the answer:
These are all valid and fine ways to call a function pointer:
myFuncPtr();
(*myFuncPtr)();
(**myFuncPtr)();
(***myFuncPtr)();
// etc.
(**********************************f)(); // also valid
Things you can do with a function pointer.
1: The first is calling the function via explicit dereference:
int myfunc(int n)
{
}
int (*myfptr)(int) = myfunc;
(*myfptr)(nValue); // call function myfunc(nValue) through myfptr.
2: The second way is via implicit dereference:
int myfunc(int n)
{
}
int (*myfptr)(int) = myfunc;
myfptr(nValue); // call function myfunc(nValue) through myfptr.
As you can see, the implicit dereference method looks just like a normal function call -- which is what you’d expect, since function are simply implicitly convertible to function pointers!!
In your code:
void foo()
{
cout << "hi" << endl;
}
class TimerOne
{
public:
void(*isrCallback)();
};
int main()
{
TimerOne Timer1;
Timer1.isrCallback = &foo; //Assigning the address
//Timer1.isrCallback = foo; //We could use this statement as well, it simply proves function are simply implicitly convertible to function pointers. Just like arrays decay to pointer.
Timer1.isrCallback(); //Implicit dereference
(*Timer1.isrCallback)(); //Explicit dereference
return 0;
}
You don't have to dereference a function pointer to call it. According to the standard ([expr.call]/1),
The postfix expression shall have
function type or pointer to function type.
So (*myFunc)() is valid, and so is myFunc(). In fact, (**myFunc)() is valid too, and you can dereference as many times as you want (can you figure out why?)
You asked:
Timer1 calls the function as follows:
Timer1.isrCallback();
How is this correct?
The type of Timer1.isrCallback is void (*)(). It is a pointer to a function. That's why you can use that syntax.
It is similar to using:
void foo()
{
}
void test_foo()
{
void (*fptr)() = foo;
fptr();
}
You can also use:
void test_foo()
{
void (*fptr)() = foo;
(*fptr)();
}
but the first form is equally valid.
Update, in response to comment by OP
Given the posted definition of the class you would use:
(*Timer1.isrCallback)();
To use
(Timer1.*isrCallback)();
isrCallback has to be defined as a non-member variable of whose type is a pointer to a member variable of TimerOne.
void (TimerOne::*isrCallback)();
Example:
#include <iostream>
class TimerOne
{
public:
void foo()
{
std::cout << "In TimerOne::foo();\n";
}
};
int main()
{
TimerOne Timer1;
void (TimerOne::*isrCallback)() = &TimerOne::foo;
(Timer1.*isrCallback)();
}
Output:
In TimerOne::foo();
(Test this code)
If you want to define isrCallbak as a member variable of TimerOne, you'll need to use:
#include <iostream>
class TimerOne
{
public:
void (TimerOne::*isrCallback)();
void foo()
{
std::cout << "In TimerOne::foo();\n";
}
};
int main()
{
TimerOne Timer1;
Timer1.isrCallback = &TimerOne::foo;
// A little complicated syntax.
(Timer1.*(Timer1.isrCallback))();
}
Output:
In TimerOne::foo();
(Test this code)
If a function takes a const & argument it should be immutable.
Why can I change values in a class passed as const?
How can I prevent a function taking const & to change values?
Note: compiles on vs2012 ad g++ 4.8.2
#include "iostream"
class Foo {
public:
Foo() : a(-99) {}
int a;
};
class Bar{
public:
Bar (Foo& f): rFoo(f), pFoo(&f), foo(f) {}
Foo& rFoo;
Foo* pFoo;
Foo foo;
};
void setA (const Bar & b){
Foo* f = new Foo();
Foo f2 = *f;
f->a = 7;
//b.foo.a = 8; // error C3490: 'a' cannot be modified because it is being accessed through a const object
//b.pFoo = f; // error C3490: 'pFoo' cannot be modified because it is being accessed through a const object
b.pFoo->a = 9; // OK... the pointer is const the location its pointing to not...
b.rFoo.a = 10; // Maybe ... the reference may be const, the location its is referencing not ...
b.rFoo = *f; // Why can I modify the reference ?
}
int main(int argc, char* argv[]){
Foo f;
Bar b(f);
std::cout << "one: " << b.rFoo.a << std::endl;
b.pFoo->a = 1;
b.foo.a = 2;
std::cout << "two: " << b.rFoo.a << std::endl;
setA(b);
std::cout << "three: " << b.rFoo.a << std::endl;
return 0;
}
Many Thanks in advance
You can modify the reference for the same reason you can modify the pointed to object by pFoo. Since you aren't modifying the objects member, but another referenced object.
b.rFoo = *f; // Foo's assignment operator invoked
That's why you should not expose members variables. Since you can't enforce a prevention to modify referenced objects, other than in your own member functions.
b.rFoo = *f
is not changing rFoo itself, it is equivalent to
b.rFoo.operator=(*f);
which copies *f to the object referenced by rFoo.
The const qualifier of an object indicates that the abstract state of this object won't change (i.e., from the client's point of view). This is not exactly the same as saying that the object's raw bits are not going to change.
It is forbitten to C++ compilers to consider objects as raw bits, unless they can resolve the problem of aliasing. which in your case the compiler cannot. This is due to the fact that Foo* pFoo is a pointer to an object and consequently the state of this object is modifiable. That is, even if the object that pFoo points to changes, the object that contains pFoo (i.e., b) doesn't change since pFoo continues to point to the same object.
Is it possible to cast from a predefined Type_pointer in c++ to its Type?
For example we defined a custom XType.
I want to do something like this, but I get an error:
XType* b;
XType a = (XType) b;
I want to pass the pointer itself to a function that only accept Type (not Type*)
You should dereference the pointer with the * operator:
struct Type {
Type(Type*) {}
};
void f(Type t) {
}
int main () {
Type a;
Type* b = &a;
// Q: how to invoke f() if I only have b?
// A: With the dereference operator
f(*b);
}
In addition to the #Robᵩ's proposal, you can change the function to accept the pointer.
Actually, if you plan to pass the pointer to other functions from within the given function, you must get the pointer (well, or a reference) as parameter, otherwise you'll get a copy of the original object as the parameter, so you'll be unable to retrieve the address of (i.e. pointer to) the original object.
If you'd like to spare the refactoring, you can do the reference trick:
void g(T* pt)
{
// ...
}
void f(T& rt) // was: void f(T rt)
{
cout << rt.x << endl; // no need to change, syntax of ref access
// is the same as value access
g(&rt); // here you get the pointer to the original t
}
T* t = new T();
f(t);
Please consider the following code.
struct foo
{
};
template<typename T>
class test
{
public:
test() {}
const T& value() const
{
return f;
}
private:
T f;
};
int main()
{
const test<foo*> t;
foo* f = t.value();
return 0;
}
t is a const variable and value() is a constant member-function which returns const T&. AFAIK, a const type is not assignable to a non-const type. But how foo* f = t.value(); compiles well. How this is happening and how can I ensure value() can be only assigned to const foo*?
Edit
I found that, this is happening on when templates are used. Following code works as expected.
class test
{
public:
test() {}
const foo* value() const { return f; }
private:
foo* f;
};
int main()
{
const test t;
foo* f = t.value(); // error here
return 0;
}
Why the problem is happening when templates are used?
Because you have two levels of indirection - in your main function, that call to value returns a reference to a const pointer to a non-const foo.
This can safely be copied into non-const pointer to a non-const foo.
If you'd instantiated test with const foo *, it would be a different story.
const test<const foo*> t;
foo* f = t.value(); // error
const foo* f = t.value(); // fine
return 0;
Update
From the comment:
value() returns const T& which can
only be assigned to another const
type. But in this case, compiler is
safely allowing the conversion.
Const data can only be read. It cannot be written ("mutated"). But copying some data is a way of reading it, so it's okay. For example:
const int c = 5;
int n = c;
Here, I had some const data in c, and I copied the data into a non-const variable n. That's fine, it's just reading the data. The value in c has not been modified.
Now, suppose your foo had some data in it:
struct foo { int n; };
If I have a non-const pointer to one of those, I can modify the n value through the pointer. You asked your test template to store a pointer to a non-const foo, and then made a const instance of test. Only the pointer address is constant, therefore. No one can change the address stored in the pointer inside test, so it cannot be made to point to another object. However, the object it points to can have its contents modified.
Update 2:
When you made your non-template version of the example, you made a mistake. To get it right, you need to substitute foo * into each place where there's a T.
const T& value() const
Notice that you have a reference to a const T there. So the return value will be a reference to something const: a foo *. It's only the pointer address that can't be modified. The object it points to can have its contents modified.
In your second example, you got rid of the reference part, which changes the meaning and makes the const modifier apply to the object that the pointer points to, instead of applying to the pointer itself.
Use the following template specialization:
template<typename T>
class test<T*>
{
public:
test() {}
const T* value() const
{
return f;
}
private:
T* f;
};
After including this, g++ says:
d.cpp: In function ‘int main()’:
d.cpp:41: error: invalid conversion from ‘const foo*’ to ‘foo*’
There's nothing wrong in your code, having a const reference to a pointer only means that you can't modify the pointer, but the pointed-to object remains perfectly mutable. If inside your main function you try to change the address pointed to by the f member of t you'll see that you can't: encapsulation is perfectly preserved.
This is the same principle that makes the following code valid:
void foo(std::vector<int *> const & v)
{
*v[0] = 0; // op. [] returns const & to int *
}
People new to C++ are usually surprised by this behavior, because for them a const vector should not allow the modification of its elements. And in fact it doesn't, because the pointer stored in the vector does not change (it keeps pointing to the same address). It's the pointed-to object which is modified, but the vector does not care about that.
The only solution is to do as Amit says and provide a specialization of your class for T*.