This article is for the readers who have a basic background of math, graphics, c++. Although I have written the code about Vector2,Vector3 by c++, but as time goes by, all the principles were forgotten. So I decided to write something about the simple program to get much more strong memory.
If you search the implementation of vector in github, you can find lots examples. Here’s an example vector.hpp, actually it’s too hard for me to read. Today’s vector.hpp is about the really basic syntax in c++ such as operator overloading, friends, inline etc.
Scan the program above, here’s some tips:
Inline functions are a C++ enhancement designed to speed up programs.
The primary distinction between normal functions and inline functions is not in how you code them but in how the C++ compiler incorporates them into a program.To understand the distinction between inline functions and normal functions,you need to peer more deeply into a program’s innards.Let’s do that now.
The final product of the compilation process is an executable program,which consists of a set of machine language instructions.When you start a program,the operating system loads these instructions into the computer’s memory so that each instruction has a particular memory address.The computer then goes through these instructions step-by-step.Sometimes,as when you have a loop or a branching statement,program execution skips over instructions,jumping backward or forward to a particular address. Normal function calls also involve having a program jump to another address (the function’s address) and then jump back when the function terminates.
Let’s look at a typical implementation of that process in a little more detail.When a program reaches the function call instruction, the program stores the memory address of the instruction immediately following the function call,copies function arguments to the stack (a block of memory reserved for that purpose),jumps to the memory location that marks the beginning of the function,executes the function code (perhaps placing a return value in a register),and then jumps back to the instruction whose address it saved. Jumping back and forth and keeping track of where to jump means that there is an overhead in elapsed time to using functions.
C++ inline functions provide an alternative.In an inline function,the compiled code is “in line” with the other code in the program.That is,the compiler replaces the function call with the corresponding function code.With inline code,the program doesn’t have to jump to another location to execute the code and then jump back.
Inline functions thus run a little faster than regular functions,but they come with a memory penalty.If a program calls an inline function at ten separate locations,then the program winds up with ten copies of the function inserted into the code.
You should be selective about using inline functions.If the time needed to execute the function code is long compared to the time needed to handle the function call mechanism,then the time saved is a relatively small portion of the entire process.If the code execution time is short,then an inline call can save a large portion of the time used by the non-inline call.On the other hand,you are now saving a large portion of a relatively quick process,so the absolute time savings may not be that great unless the function is called frequently.
The inline facility is an addition to C++. C uses the preprocessor #define statement to provide macros, which are crude implementations of inline code. For example, here’s a macro for squaring a number:
This works not by passing arguments but through text substitution, with the X acting as a symbolic label for the “argument”:
a = SQUARE(5.0); is replaced by a = 5.0*5.0;
Only the first example here works properly. You can improve matters with a liberal application of parentheses:
Still, the problem remains that macros don’t pass by value. Even with this new definition, SQUARE(c++) increments c twice, but the inline square() function evaluates c , passes that value to be squared, and then increments c once. The intent here is not to show you how to write C macros.
Rather, it is to suggest that if you have been using C macros to perform function-like services, you should consider converting them to C++ inline functions.
The main use for a reference variable is as a formal argument to a function.If you use a reference as an argument,the function works with the original data instead of with a copy.References provide a convenient alternative to pointers for processing large structures with a function,and they are essential for designing classes.
‘&’ in c++ has two functions:
to indicate the address of a variable
to declare references
In this context, & is not the address operator.Instead,it serves as part of the type identifier.
Just as char * in a declaration means pointer-to-char , int & means reference-to-int .The reference declaration allows you to use rats and rodents interchangeably;both refer to the same value and the same memory location.
int rats = 101;
Then you could use the expressions rodents and *prats interchangeably with rats and use the expressions &rodents and prats interchangeably with &rats .From this standpoint,a reference looks a lot like a pointer in disguised notation in which the * dereferencing operator is understood implicitly.And,in fact,that’s more or less what a reference is.But there are differences besides those of notation.For one,it is necessary to initialize the reference when you declare it;you can’t declare the reference and then assign it a value later the way you can with a pointer:
You should initialize a reference variable when you declare it.
A reference is rather like a const pointer;you have to initialize it when you create it, and when a reference pledges its allegiance to a particular variable,it sticks to its pledge. That is,
int & rodents = rats; (equals to) int * const pr = & rats;
The result is :
wallet1 = $300 wallet2 = $350
The reference and pointer methods both successfully swap the contents of the two wallets,whereas the passing by value method fails.
Operator overloading is a technique for giving object operations a prettier look.
Operator overloading is an example of C++ polymorphism.
As you’ve seen,C++ controls access to the private portions of a class object.Usually,public class methods serve as the only access,but sometimes this restriction is too rigid to fit particular programming problems.In such cases,C++ provides another form of access:the friend.Friends come in three varieties:
Friend member functions
Often,overloading a binary operator (that is,an operator with two arguments) for a class generates a need for friends Multiplying a Time object by a real number provides just such a situation,so let’s study that case.
A = B * 2.75;
Remember,the left operand is the invoking object.
Translates to the following member function call:
A = B.operator*(2.75);
But what about the following statement?
A = 2.75 * B; // cannot correspond to a member function
Conceptually, 2.75 * B should be the same as B * 2.75 ,but the first expression cannot correspond to a member function because 2.75 is not a type Time object.Remember, the left operand is the invoking object,but 2.75 is not an object.So the compiler cannot replace the expression with a member function call.
One way around this difficulty is to tell everyone (and to remember yourself) that you can only write B * 2.75 but never write 2.75 * B .This is a server-friendly,client-beware solution,and that’s not what OOP is about.
However,there is another possibility—using a nonmember function.(Remember,most operators can be overloaded using either member or nonmember functions.) A nonmember function is not invoked by an object;instead,any values it uses,including objects,are explicit arguments.Thus,the compiler could match the expression
Time operator*(double m, const Time & t);
Using a nonmember function solves the problem of getting the operands in the desired order (first double and then Time ),but it raises a new problem:Nonmember functions can’t directly access private data in a class.Well,at least ordinary nonmember functions lack access.But there is a special category of nonmember functions,called friends,that can access private members of a class.
The first step toward creating a friend function is to place a prototype in the class declaration and prefix the declaration with the keyword friend . Like the code we showed in the beginning.
friend Vector3f operator*(const float& r, const Vector3f& v)
This prototype has two implications:
Although the operator*() function is declared in the class declaration,it is not a member function.So it isn’t invoked by using the membership operator.
Although the operator*() function is not a member function,it has the same access rights as a member function.
At first glance, it might seem that friends violate the OOP principle of data hiding because the friend mechanism allows nonmember functions to access private data. However, that’s an overly narrow view. Instead, you should think of friend functions as part of an extended interface for a class. For example, from a conceptual point of view, multiplying a double by a Time value is pretty much the same as multiplying a Time value by a double . That the first requires a friend function whereas the second can be done with a member function is the result of C++ syntax, not of a deep conceptual difference. By using both a friend function and a class method, you can express either operation with the same user interface. Also keep in mind that only a class declaration can decide which functions are friends, so the class declaration still controls which functions access private data. In short, class methods and friends are simply two different mechanisms for expressing a class interface.
From the code in the begining,we see that :
friend std::ostream& operator<<(std::ostream& os, const Vector3f& v)
In its most basic incarnation,the << operator is one of C and C++’s bit manipulation operators;it shifts bits left in a value.But the ostream class overloads the operator,converting it into an output tool.Recall that cout is an ostream object and that it is smart enough to recognize all the basic C++ types.That’s because the ostream class declaration includes an overloaded operator<<() definition for each of the basic types.That is,one definition uses an int argument,one uses a double argument,and so on.So one way to teach cout to recognize a Vector3f object is to add a new function operator definition to the ostream class declaration.But it’s a dangerous idea to alter the iostream file and mess around with a standard interface. Instead,use the Vector3f class declaration to teach the Vector3f class how to use cout.
So this is the basic syntax, anyway, there’s still lots deeper knowledge there… if I have met much more advanced code, I will write this article again.
C++ Primer Plus.
Your Majesty, coding and blogging is hard, but a cup of tea/coffee would be the best reward. Scan the QRcode below, I’ll swear my allegiance to you. :) memeda