Object: Functions, parameters and Data StructuresTrail Index | Objects | Functions Going from a naive implementation of 2 functions to a clean, structured one in which duplication has been removed. Step 1 - Basic/* * Objects: two identical functions with separate parameters. * Easy to mix up variable names.. */ #include <iostream> #include <cmath> double k1; // global, non const, not initialized double k2; // global, non const, not initialized double f1(const double x) { return sqrt(k1)*x+k2*x*x; } double ka; // global, non const, not initialized double kb; // global, non const, not initialized double f2(const double x) { return sqrt(ka)*x+k2*x*x; // whoops should have been kb, not k2 ! // the compiler will not help you here } int main() { k1=2.; k2=3.; const double y1=f1(3.); std::cout<< "f1("<<3.<<")="<<y1<<"\n"; ka=4.; kb=5.; const double y2=f2(3.); std::cout<< "f2("<<3.<<")="<<y2<<" - wrong!!\n"; } Step 2 - Choose better variable names/* * Objects: two identical function with parameters. * Parameter names specify what they are related to. * Cleaner, safer, but verbose */ #include <iostream> #include <cmath> /* * prepend function name to parameter name, * in this case using "_", * which has no syntactical meaning for C++: * it's like any other letter or number */ double f1_k1; double f1_k2; double f1(const double x) { return sqrt(f1_k1)*x+f1_k2*x*x; } double f2_ka; // could have called it f1_k1 double f2_kb; double f2(const double x) { return sqrt(f2_ka)*x+f2_kb*x*x; // OK now } /** * nothing different here */ int main() { f1_k1=2.; f1_k2=3.; const double y1=f1(3.); std::cout<< "f1("<<3.<<")="<<y1<<"\n"; f2_ka=4.; f2_kb=5.; const double y2=f2(3.); std::cout<< "f2("<<3.<<")="<<y2<<"\n"; } Step 3 - Use, and reuse, a data structureA class or struct is like a mould to make objects. From one class, you can create many "instances". But if you don't give too much importance to the titles, this is not anything new: like you have multiple variables of type double, you have multiple variables of type DataPoint. /* * two functions with parameters in struct * Clearer, but still verbose, still possible to mix it up * Note: this would be reasonably good plain C (not C++) code */ #include <iostream> #include <cmath> /** * data structure, * groups together the related variables * (function parameters, in this case) * * This is just a "definition", not a "declaration" * it does not really create a variable, * it only defines a new type */ struct FunctionParameters { double k1; double k2; }; /** * Declare an "instance" of the data structure, * * This is called "instantiating an object" * Must declare it before the function! * So it still needs to be global */ FunctionParameters fp1; /** * the function is not really different from before * Just note the use of "." to identify instance.variable */ double f1(const double x) { return sqrt(fp1.k1)*x+fp1.k2*x*x; } FunctionParameters fp2; double f2(const double x) { return sqrt(fp2.k1)*x+fp2.k2*x*x; } /** * usage of f1 and f2 is very similar, * just note the fp1.k1 instead of f1_k1 */ int main() { fp1.k1=2.; fp1.k2=3.; const double y1=f1(3.); std::cout<< "f1("<<3.<<")="<<y1<<"\n"; fp2.k1=4.; fp2.k2=5.; const double y2=f2(3.); std::cout<< "f2("<<3.<<")="<<y2<<"\n"; } Step 4 - struct as parameter/** * two functions with parameters in struct * Clearer, but still verbose, still possible to mix it up * Note: this would be reasonably good plain C (not C++) code */ #include <iostream> #include <cmath> /** * data structure as in Function_3 * Still only a definition, not declaration. */ struct FunctionParameters { double k1; double k2; }; /** * now we pass all parameters to the function. * In this way we only write the function once, * and we do not need globals! */ double f(const FunctionParameters fp, const double x) { return sqrt(fp.k1)*x+fp.k2*x*x; } /** * The usage of f() is now quite different, * we must pass it the whole instance of struct as parameter * Note that we don't need the globals anymore, * we can create the instances of struct where we need them! */ int main() { { FunctionParameters fp1; // create instance, locally! fp1.k1=2.; fp1.k2=3.; const double y1=f(fp1,3.); // looks odd, doesn't it? std::cout<< "f1("<<3.<<")="<<y1<<"\n"; } /* * now using separate scopes, it's * impossible to confuse fp1 and fp2 */ { FunctionParameters fp2; fp2.k1=4.; fp2.k2=5.; const double y2=f(fp2,3.); std::cout<< "f2("<<3.<<")="<<y2<<"\n"; } } < Objects | Trail Index | Objects > |