The text I'm following says:
A call to a virtual function using an object is always resolved statically. You only get a dynamic resolution through a pointer or a reference.
Now consider the following program:
#include <iostream>
class Mainclass{
protected:
double length{1.0};
double width{1.0};
double height{1.0};
public:
Mainclass(double lv, double wv, double hv):length{lv}, width{wv}, height{hv}{
std::cout<<"Three args box ran"<<std::endl;
}
void showVolume() const{
std::cout<<"Mainclass usable volume is: "<<Volume()<<std::endl;
}
virtual double Volume() const{
return length*width*height;
}
};
class Derivedclass: public Mainclass{
public:
Derivedclass(double lv, double wv, double hv): Mainclass{lv, wv, hv}{}
double Volume() const{
return 0.85*length*width*height;
}
};
int main(){
Mainclass first{20.0, 30.0, 40.0};
Derivedclass second {20.0, 30.0, 40.0};
first.showVolume();
second.showVolume();
}
Output:
Three args box ran
Three args box ran
Mainclass usable volume is: 24000
Mainclass usable volume is: 20400
Here, I'm calling the base class and the derived class objects via their object instances and not through a pointer. But it appears that the function is being resolved dynamically. Was the text wrong? If not what did it mean?
"A call to a virtual function using an object is always resolved statically. You only get a dynamic resolution through a pointer or a reference."
This sentence isn't so much describing a rule of the C++ language as a shortcut compilers are allowed to take.
You are calling showFunction directly on the names of objects. So suppose showFunction were declared virtual. The compiler knows the exact types of the objects called first and second: there's no way they could actually be objects of some other type. So although the language says any overriding function must be called by first.showVolume() and second.showVolume(), there's no possible way the result will be any functions other than the ones the compiler can find immediately, so it doesn't actually need to put any code for determining which function to call in the resulting program. The correct function Mainclass::showVolume() (or Derivedclass::showVolume(), if it existed), can be called directly, which can be slightly more efficient.
The quote doesn't apply to the call of Volume() inside showVolume(). Since Volume names a non-static member, Volume() means the same as this->Volume(). this is a pointer, which might or might not point at an object whose complete type matches the type Mainclass* const of the pointer. So in this case, the compiler is required to do dynamic resolution to determine which function to call.
But one more thing to note: it's true you can only get dynamic resolution through a pointer or reference, but it's not true you always get dynamic resolution through a pointer or reference. When a function is named as a "qualified id" using the :: token, the language says the function called is determined statically, and overrides are ignored. For example, if your code in showVolume() changed to use either Mainclass::Volume() or this->Mainclass::Volume(), you would see that it never calls Derivedclass::Volume.
Related
I am new to c++ and im trying to write a simple c++ wrappers to integrate with this third party c++ library; which comes with bad documentation.
function to integrate with (this is all the documentation that came with this function):
virtual ImageCoord Raster::groundToImage(const XyzCoord & groundPt,
double desiredPrecision=0.001,
double* achievedPrecision=null) const
Text about function: This method converts the given groundPt (x,y,z in meters) to a returned image coordinate (line, sample in full image space pixels).
there is also some class documentation
Raster Class Ref
inherits from GeoModel
Public member functions:
virtual ImageCoord groundToImage (const XyzCoord &groundPt, double desiredPrecision=0.001, double *achievedPrecision=NULL) const =0
in my code i have:
//this is implemented correctly
const XyzCoord xyz(284971.17549099098, -126866.36533847413, 6350003.627515804)
double desiredPrecision = 0.000001;
double achievedPrecision = 0.0;
// not sure if this is what the documentation meant by "image coordinate" but it comes with the library
// ImageCoord(double line, double point)
ImageCoord imagePoints;
// the part im confused about, what is the proper way to invoke the above function, the below line was me trying out how to call the method
const Raster::groundToImage(&xyz, imagePoints);
Sorry for my ignorance in c++ but I've been baffled. I have lot of programing experience (8 plus years, just none with c++ so i understand programing terms, concepts and design patterns).
Im also trying to understand in the function defination what does this mean
const XyzCoord & groundPt
I was able to compile with
XyzCoord xyz(204971.17549099098, -106866.36533847413, 6350003.627515804);
Raster* service;
ImageCoord imagePoints = service->groundToImage(xyz); //segmentation error occurs on this line
but i then get a runtime error "Segmentation fault"
This is a non-static member function of a class named Raster.
You are supposed to invoke it via member access obj.groundToImage(/*args*/) where obj is an object of the class type to which the function belongs or a class type derived from that class.
Or, if the call happens inside another non-static member function of the same class or a derived class, it could just be groundToImage(/*args*/) which will call the function implicitly on the current object.
With virtual it may also be possible to invoke the function on an object of a base class of Raster, depending on where the virtual function has been declared first in the class hierarchy.
There are certain more specialized situations where a qualified call replacing groundToImage with Raster::groundToImage in either of the above could also be the intended behavior.
The const qualification of the function is irrelevant. It just means that the function can be called whether obj is const-qualified or not. Similarly the const-qualification on the function parameter is irrelevant. It just means that you can pass either a const- or non-const-qualified first argument. You don't have to make xyz const to be able to pass it. Only the other way around, passing a const-qualified expression to a non-const reference parameter is a problem. const is intended to signal that the function will not modify the argument and therefore doesn't care whether or not it is const-qualified.
const only makes sense when used in a declaration or type. Something like
const Raster::groundToImage(&ecef, imagePoints)
as a supposed function call doesn't make syntactical sense.
The function also expects up to three arguments of the specified types and returns a ImageCoord. You are not supposed to pass one as an argument. It is what the function returns.
The arguments should probably be xyz, desiredPrecision and &achievedPrecision given that you already declared them with the correct types.
It probably wants the last one as pointer because it is an out-parameter.
What the object on which the member function is called on is supposed to be is unclear from what you have shown. We don't know what ecef is though...
TL;DR:
ImageCoord imagePoint = someRasterObject.groundToImage(
xyz,
desiredPrecision,
&achivedPrecision
);
Or
ImageCoord imagePoint = somePointerToRasterObject->groundToImage(
xyz,
desiredPrecision,
&achivedPrecision
);
From the signature given:
virtual // A derived class's implementation of
// this function can be called via a
// pointer or reference to a parent
// class object
ImageCoord // This function returns an ImageCoord
// object
Raster:: // This is a member of the Raster class
groundToImage( // This function is named groundToImage
const XyzCoord & groundPt, // The first argument to this function is a
// reference to a constant XyzCoord
// object
double desiredPrecision=0.001, // The second argument is a double with a
// default value of 0.001 if not provided
double* achievedPrecision=null // The third argument is a pointer to a
// double with a default value of null if
// not provided
)
const // This function can be called on a
// constant Raster object
That means you need 2-4 things to call this function:
A (possibly const-qualified) Raster object to call the function on
An XyzCoord object to pass as the first parameter
(Optional) A double to pass as the second parameter
(Optional) A pointer to a double to pass as the third parameter
While nothing in your question explicitly states it, I would assume the function uses the 3rd parameter as an output. I would assume it writes the actually achieved precision to the double pointed to by the pointer you pass it, so you'll probably want to just pass it the address of a local double variable.
Each non-static method in a class is called on behalf of some object of that class (or some derived class), and the object is accessible within a method by an implicitly defined this pointer.
The const qualifier appended after the parameters' list of the method applies to that this value. In other words, it declares this of a type classname const* instead of classname*.
As a result the compiler will reject any attempts to modify the *this object from within the const-qualified method, so the method can be safely used on non-modifiable objects.
For example, the length() method of the std::string class is declared as
size_t length() const;
so when you use it like, say:
std:string s;
....
size_t len = s.length();
you can be sure the s variable will not be modified during calculation of len value.
I have a virtual get method that looks like this in the super class:
virtual double getPortagem() const;
double via_Ligacao::getPortagem() const
{
return 0;
}
And in their "child":
double getPortagem();
double auto_Estrada::getPortagem()
{
return portagem;
}
The thing that is bugging me is if I declare the child method as non const the results will be accoding to the values inserted but if I declare as a const method it will return me a memory position. Could you guys explain me this, please?
function overriding is not being done as you are making a new function in the child classes by declaring non const function which is not getting any match with the function in the superclass.
In C++11 you can use the keyword override to ensure that an intended override really is an override:
double auto_Estrada::getPortagem() override
{
return portagem;
}
Then you get a compilation error if it isn't an override, which this non-const function isn't (since it differs in const-ness from the base class method of the same name).
Instead of overriding the base class function this function shadows the base class function, so that if you call o.getPortagem() where o is const and of class auto_Estrada, the compiler won't find the base class const function, and complain.
In C++03 about the best you could do was to statically assert that the same named base class function could be called with the same arguments (it helped but wasn't guaranteed). Note that C++03 didn't have a static_assert. The usual way to do C++03 static asserts was via a typedef of an array, with negative size where you wanted a compile time error.
Regarding terminology,
what you call a "child class" is a derived class (C++ terminology) or subclass (more general computer science terminology, I believe originally from Smalltalk),
what you call "memory position" appears to be arbitrary bits in an uninitialized variable, interpreted as a floating point value, which is called an indeterminate value.
It's formally Undefined Behavior to use an indeterminate value, so anything can happen.
Let's assume there is a kind of a function, which could be both global function or could be implemented as class member const function (not static, static means global). It depends on user's choice if the function will be called or not called at all. Let say - It is usually not called or called rare - in very special cases.
I am not interested of the program's logic organization. My question is about the memory usage. I know that data member function costs a little bit more (one pointer more), since it is called trough an object. What about the case if the function is not called in runtime?
If it is global function it will be resident in memory during program's lifelong no matter it is called or not. What about the case of data member function, since it is called through and object that is dynamically created, respectively - not created at all, what about the memory needed for the function, where it will be placed and what happens if an object is not created at all?
Thanks.
As was mentioned in the comments, a class member function in C++ can be thought of as a normal C-style function which implicitly takes as an argument a pointer to the instance of the class from which it is called. For example, consider the following C++ code:
class foo {
public:
void set(int j);
private:
int i;
};
void foo::set(int j) {
i = j;
}
The function foo::set can be thought of a C-style function which takes a (hidden) argument of type class foo *, and when you do foo a; a->set(3);, the class foo * that is (implicitly) passed is &a.
In summary, whether or not you ever call foo::set, it will be loaded into memory. (The only possible exception is if there are no calls to the function in your code at all, in which case an optimizer may remove it during compilation, but if it is possible to call it dynamically based on user input then it will be loaded.) On the other hand, no matter how many instances of class foo you have, only one copy of foo::set ever needs to exist in memory.
If your function isn't virtual then there is no overhead of being a member function (aka method).
In fact, in generated object code there is no such notion of a "member function" (unless it's virtual, more on that later). All methods are functions with special variable this. Compiler at the compile time knows what method is to be called at the run time, so it can generate method-specific object code (with some handling of this). By the way, that's the case why the following code doesn't crash:
#include <iostream>
class Crashy {
public:
void wouldItCrash() {
std::cout << "Hey, I'm still alive!" << std::endl;
}
};
int main() {
Crashy* ptr = 0;
ptr->wouldItCrash();
return 0;
}
Despite of null pointer there, programs successively finishes and prints "Hey, I'm still alive!". And that's okay if you think about method wouldItCrash as some kind of a function with special parameter this:
#include <iostream>
void Crashy__wouldItCrash(Crashy *this) {
std::cout << "Hey, I'm still alive!" << std::endl;
}
int main() {
Crashy* ptr = 0;
Crashy__wouldItCrash(ptr);
return 0;
}
We don't dereference the pointer in function, so no problems happen.
Consider the following simple program:
#include <iostream>
void FunctionName__() {
std::cout << "Hello from function!" << std::endl;
}
class ClassName__ {
public:
void MethodName1__() {
std::cout << "Hello from method 1!" << std::endl;
}
void MethodName2__() {
std::cout << "Hello from method 2!" << std::endl;
}
};
int main() {
FunctionName__();
ClassName__ a;
a.MethodName1__();
a.MethodName2__();
return 0;
}
If you compile it without optimizations (just g++ main.cpp) and then look at the symbols table (nm a.out), you'll see
0804876d T _Z14FunctionName__v
...
0804882c W _ZN11ClassName__13MethodName1__Ev
08048858 W _ZN11ClassName__13MethodName2__Ev
That is, all methods became just plain functions with special names (so no conflict could happen, see name mangling)
Virtual functions
As I said earlier, there are some special rules applying to the virtual functions. Virtual functions cannot be resolved at the compile-time (compiler doesn't know which instance of derived class will be processed at the run-time), so it's delayed to the run-time. So in order to serve virtual functions, each class (with that kind of functions, of course) has a special lookup table named virtual method table (aka vtable). In that case you clearly pay some memory space: you need a pointer to the function in the vtable and a pointer to the vtable for each instance of your class.
In typical C++ implementations:
A function is a function, regardless of whether it's a member function of some class, and it will reside in memory "forever" (disregarding demand-paging and all that).
A non-virtual member function is nothing more than an ordinary function that takes a hidden argument called this.
A virtual member function is a member function that has its address recorded in a dispatch table for the class that it belongs to.
So member functions are very much like ordinary functions, the main thing that changes is the way the call is done: with an additional argument, and possibly through a hidden function pointer.
This is probably something elementary, I have a function from one class (called cell) with identifier woo_func_ptr taking a pointer to function of type void with no arguments (void (*void_ptr)(void)) (which I typedef). In another class, I have an object of cell and I use the method woo_func_ptr. It won't allow me to, I get the error in the above title. If these two functions were not embedded inside a class, they would work fine
typedef void (*void_ptr)(void);
double WOO{0};
struct cell {
void woo_func_ptr(void_ptr jo)
{
jo();
}
};
class woosah
{
public:
void woo_func()
{
WOO+=rand();
std::cout << WOO << std::endl;
};
void run()
{
// other stuff
temp_cell.woo_func_ptr(woo_func);
// yet more stuff
}
cell temp_cell;
};
First of all pointer to woosah member function should be declared as
typedef void (woosah::*void_ptr)(void);
and then compiler would complain that it needs to see woosah definition while parsing this statement.
If you let compiler parse class woosah first by moving it up then it will complain that type cell is not defined (since it is contained within woosah). That wil still not solve your problem because of cyclic dependency while parsing.
One way is to solve cyclic dependency is by making temp_cell a pointer to cell instance and have it contained within woosah.
Also note, the syntax to call member function is by using .* or ->*
void run()
{
// other stuff
temp_cell->woo_func_ptr(temp_cell->*woo_func); // assuming temp_cell is pointer to some cell instance
// yet more stuff
}
http://msdn.microsoft.com/en-us/library/b0x1aatf(v=vs.80).aspx shows similar errors and their fixes.
A member function is not like a regular function. That's why there's a seperate "pointer to member function" type. It's because member functions are passed the implicit this pointer.
In fact, the standard even limits (severly) the casting of pointer to member function.
That's the source of your error.
You could use a static class function...
Change
void woo_func()
to
static void woo_func()
This will of coarse may not be what you want if you are trying to access data members of a particular object.
Member functions are kind of special and should not be treated as normal functions.
I created a class with two get methods, one const and one non-const. The const method is public, so users can query the vector. The non-const method is protected, so I can use it to modify the data I need.
When I try to use the class, however, and call the get method, the compiler complains that the non-const method is protected. Instead, I have to use const_cast to cast the object to const, so I can get instead the public method.
Is there a way to solve this? Why wouldn't the compiler do the cast itself, since there is a public method? If I remove the protected version and just leave the const one, it works fine, so it does do the cast in this situation. Casting to const is always safe. It's removing constness that is a problem.
Member access control is the very last thing that occurs when calling a member function. It happens after name lookup, template argument deduction, overload resolution, and so on. The reason why it is done last is because it was decided that changing the access control for a member should not suddenly change the execution of client code.
Imagine access was checked before overload resolution, and you used a library and a certain member function in that library. Then the library authors made the function private. Suddenly, your code starts using a different overload and behaves in a completely different way. The library authors probably intended that anybody using that overload of the function should stop using it, but they didn't intend to change everybody's code. However, as the standard is actually defined, your code would now start giving you an error for using a private member, rather than behave differently.
The solution is to simply change the name of your protected member function so that it isn't considered.
The compiler considers accessibility after it decides what member function it wants to call. That is, protected and private functions are still visible, even though they aren't accessible.
Why? One reason is that if you made inaccessible functions ignored by overload resolution, you could change what function is called simply by changing its accessibility. With the current rules, you can only cause compiling code to fail to compile, or cause code that currently doesn't work to compile, or change something with no effect on the meaning of the code. You cannot change access specifiers and silently cause a different function to be called.
As a contrived example, here's a pretty terrible class interface:
public:
// Returns the amount of change tendered for this transaction.
MoneyAmount change() const;
private:
// Account for a change of currency. Charges standard moneychanger's fee.
MoneyAmount change(Currency toCurrency = Currency::USD);
If inaccessible functions were removed from overload resolution, client code could call change() just fine. And if later the second change(Currency) function was made public and the first one deleted, that code would suddenly silently call another function with an entirely different purpose. The current rules prevent a change of access specifier from changing the behavior of a compiling program.
In C++, method selection (overloading resolution) happens before considering public/private access control.
Use a protected setter method instead (or data member) instead of the non const getter method.
It makes no difference if you have s.th. like
class A {
SomeType foo_;
protected:
SomeType& foo() { return foo_; }
public:
const SomeType& foo() const { return foo_; }
};
or
class A {
protected:
SomeType foo_;
public:
const SomeType& foo() const { return foo_; }
};
That is the nature behavior of C++, if the caller code the object of the class is non-const so the non-conversion, which is defined as protected one. You need defined the object of class as const or use const-cast on the object of the class, which will result that the const version of the method will be called.
#include <iostream>
class Foo {
public:
const void bar() const { std::cout << " const version called\n";}
protected:
void bar() { std::cout << " non const version called\n";}
};
int main(int argc, char** argv)
{
const Foo c;
c.bar(); // -> work
Foo c1;
c1.bar(); // compiler complain -> void Foo::bar() is protected
const_cast<const Foo&>(c1).bar(); // fine
}