Cpp Chapter 11: Working with Classes Part2

11.5.3 An implementation comment

) The separation of interface from implementation is one of the goals of OOP.

) Example of the implementation of the class Vector in a rand walk simulation:

// randwalk.cpp -- using the Vector class
// compile with the vect.cpp filebuf
#include <iostream>
#include <cstdlib>
#include <ctime>
#include "vect.h"
int main()
{
    using namespace std;
    using VECTOR::Vector;
    srand(time(0)); // seed random-number generator
    double direction;
    Vector step;
    Vector result(0.0, 0.0);
    unsigned long steps = 0;
    double target;
    double dstep;
    cout << "Enter target distance (q to quit): ";
    while (cin >> target)
    {
        cout << "Enter step length: ";
        if (!(cin >> dstep))
            break;

        while(result.magval() < target)
        {
            direction = rand() % 360;
            step.reset(dstep, direction, Vector::POL);
            result = result + step;
            steps++;
        }
        cout << "After " << steps << " steps, the subject has the following location:\n";
        cout << result << endl;
        result.polar_mode();
        cout << "or\n" << result << endl;
        cout << "Average outward distance per step = " << result.magval() / steps << endl;
        steps = 0;
        result.reset(0.0, 0.0);
        cout << "Enter target distance (q to quit): ";
    }
    cout << "Bye!\n";
    cin.clear();
    while (cin.get() != ‘\n‘)
        continue;
    return 0;
}

Noteworthy:

1 The program uses "using VECTOR::Vector;"" to attain access to the Vector::POL enumeration for later use

2 C++ includes a rand() functiono to yield an integer range from 0 to implementation-dependent value. If you want smaller range, use rand() modulus the range you desired. Actually, the rand() is really pseudorandom because rand() works by applying an algorithm to an initial seed value to get a random value. So when you call the function consecutively for 10 times, it might yield 10 same numbers. To prevent the problem, use this code:

srand(time(0));

time(0) returns the current calendar time, which is based on seconds. Then srand() uses the time integer to set the initial seed, making the numbers more random. The cstdlib header file contains srand() and rand(), while ctime contains the time() prototype.

3 Incidentally, the following statement will set result automatically to form RECT:

result = result + step;

11.6 Automatic conversions and type casts for classes

) C++ does automatic type casts for built-in types. For user-defined types, one-argument constructor is taken as the type conversion:

class Stonewt
{
    ...
}
...
Stonewt::Stonewt(double lbs)
{
    ...
}
...
Stonewt myCat;
myCat = 19.6; // use Stonewt(double lbs) to automatically convert double to type Stonewt

) But this implicit conversion may lead to trouble, so C++ adds a keyword explicit to turn off the implicit conversion. You can use explicit in the constructor declaration, cutting of implicit conversions but still leaving explicit conversions valid:

Stonewt myCat;
myCat = 19.6; // invalid, implicit conversion is banned with keyword explicit
myCat = Stonewt(myCat); // ok, explicit conversion allowed

) Implicit typc conversion(such as double to Stonewt) may occur under certain circumstances:

1 initialize a Stonewt object to a type double value

2 assign a type double value to a Stonewt object

3 pass a type double value to a function that expects a Stonewt argument

4 a function which is declared to return Stonewt but trying to return double

5 When any preceding situations use a built-in type that can unambiguously be converted to double

) Example:

// stonewt.h -- definition for the Stonewt class
#ifndef STONEWT_H_INCLUDED
#define STONEWT_H_INCLUDED

class Stonewt
{
private:
    static const int Lbs_per_stn = 14;
    int stone;
    double pds_left;
    double pounds;
public:
    Stonewt(double lbs);
    Stonewt(int stn, double lbs);
    Stonewt();
    ~Stonewt();
    void show_lbs() const;
    void show_stn() const;
};

#endif // STONEWT_H_INCLUDED
// stonewt.cpp -- Stonewt methods
#include <iostream>
#include "stonewt.h"
using std::cout;

Stonewt::Stonewt(double lbs)
{
    stone = int(lbs) / Lbs_per_stn;
    pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
    pounds = lbs;
}

Stonewt::Stonewt(int stn, double lbs)
{
    stone = stn;
    pds_left = lbs;
    pounds = stn * Lbs_per_stn + lbs;
}

Stonewt::Stonewt()
{
    stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()
{
}

void Stonewt::show_stn() const
{
    cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs() const
{
    cout << pounds << " pounds\n";
}
// stonewt.cpp -- Stonewt methods
#include <iostream>
#include "stonewt.h"
using std::cout;

Stonewt::Stonewt(double lbs)
{
    stone = int(lbs) / Lbs_per_stn;
    pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
    pounds = lbs;
}

Stonewt::Stonewt(int stn, double lbs)
{
    stone = stn;
    pds_left = lbs;
    pounds = stn * Lbs_per_stn + lbs;
}

Stonewt::Stonewt()
{
    stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()
{
}

void Stonewt::show_stn() const
{
    cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs() const
{
    cout << pounds << " pounds\n";
}

11.6.1 Conversion functions

) You could also convert user-defined types to built in types, using conversion functions in C++. The form of the function is operator typenName();:

operator int();
operator double():

) The conversion function must be a class method, ** does not specify return type** and has no arguments.

class thing
{
    ...
public:
    operator int() const;
};
...
thing::operator int() const
{
    return int(...);
}

) Examples:

// stonewt1.h -- revised definition for the Stonewt class
#ifndef STONEWT1_H_INCLUDED
#define STONEWT1_H_INCLUDED

class Stonewt
{
private:
    static const int Lbs_per_stn = 14;
    int stone;
    double pds_left;
    double pounds;
public:
    Stonewt(double lbs);
    Stonewt(int stn, double lbs);
    Stonewt();
    ~Stonewt();
    void show_lbs() const;
    void show_stn() const;
    operator int() const;
    operator double() const;
};

#endif // STONEWT1_H_INCLUDED
// stonewt1.cpp -- Stonewt methods + conversion functions
#include <iostream>
#include "stonewt1.h"
using std::cout;

Stonewt::Stonewt(double lbs)
{
    stone = int(lbs) / Lbs_per_stn;
    pds_left = int(lbs) % Lbs_per_stn + lbs - int(lbs);
    pounds = lbs;
}

Stonewt::Stonewt(int stn, double lbs)
{
    stone = stn;
    pds_left = lbs;
    pounds = stn * Lbs_per_stn + lbs;
}

Stonewt::Stonewt()
{
    stone = pounds = pds_left = 0;
}

Stonewt::~Stonewt()
{
}

void Stonewt::show_stn() const
{
    cout << stone << " stone, " << pds_left << " pounds\n";
}

void Stonewt::show_lbs() const
{
    cout << pounds << " pounds\n";
}

Stonewt::operator int() const
{
    return int(pounds + 0.5);
}

Stonewt::operator double() const
{
    return pounds;
}
// stone1.cpp -- user-defined conversion functions
// compile with stonewt1.cpp
#include <iostream>
#include "stonewt1.h"

int main()
{
    using std::cout;
    Stonewt poppins(9, 2.8);
    double p_wt = poppins;
    cout << "Convert to double => ";
    cout << "Poppins: " << p_wt << " pounds.\n";
    cout << "Convert to int => ";
    cout << "Poppins: " << int(poppins) << " pounds.\n";
    return 0;
}

) Noteworthy:

1 Using cout with type casts may produce ambiguity:

cout << poppins << endl;

The compiler doesn‘t know whether to convert poppins to double or to int, which are both defined conversions, so it raises an ambiguous error

2 Similar problem comes with assignment:

long gone = poppins; 

Both double and int could be converted to long, so the compiler doesn‘t know whether to convert poppins to double or int first, later to long, so it raises an error. If only one conversion is defined, the compiler would accept it

) The moral is to use explicit conversions to exclude the possibility of implicit conversions.


11.6.2 Conversions and Friends

) As mentioned earlier, you could use either a member function or a friend function to overload addition. See following examples:

NO.1

Stonewt jennySt(9, 12);
Stonewt bennySt(12, 8);
Stonewt total;
total = jennySt + benntSt;

the addition sentence could be matched with both member and friend forms:

total = jennySt.operator+(bennySt);
total = operator+(jennySt, bennySt);

NO.2

Stonewt jennySt(9,12);
double kennyD = 176.0;
Stonewt total;
total = jennySt + kennyD;

the addition sentence could be matched with both member and friend forms:

total = jennySt.operator+(kennyD); // here kennyD is converted to class Stonewt because the operator+() wants a Stonewt and the conversion is valid
total = operator+(jennySt, kennyD); // same, converting kennyD to Stonewt as a function parameter

NO.3(!)

Stonewt jennySt(9,12);
double pennyD = 146.0;
Stonewt total;
total = pennyD + jennySt;

The addition line could only be performed using the friend form:

total = pennyD.operator+(jennySt); // INVALID! pennyD is type double thus could not invoke operator+() method
total = operator+(pennyD, jennySt); // valid, pennyD is converted to Stonewt as function argument

Remember, conversion takes place for member function arguments, not for member function invokers.

) Choices in implementing addition

NO.1 Use a friend function and have the constructor to handle conversion of double to Stonewt:

operator+(const Stonewt &, const Stonewt &);

NO.2 Overload the addition operator with functions that explicitly use type double argument:

Stonewt operator+(Stonewt & s); // member function
friend Stonewt operator+(double x, Stonewt & s);

The first program is shorter but consumes more time, the second is longer but runs faster



Cpp Chapter 11: Working with Classes Part2

原文地址:https://www.cnblogs.com/fsbblogs/p/9770762.html

时间: 2024-07-29 23:19:42

Cpp Chapter 11: Working with Classes Part2的相关文章

Cpp Chapter 10: Objects and Classes Part2

10.2.4 Using classes Following exapmle uses the class definition and implementation written in previous files: // usestok0.cpp -- the client program // compiler with stock00.cpp #include <iostream> #include "stock00.h" int main() { Stock s

Cpp Chapter 12: Classes and Dynamic Memory Allocation Part2

12.3 Things to remember when using new in constructors ) If you use new in constructors, use delete in destructor. Their use should be compatible, pair new with delete and new [] with delete [] ) Multiple constructors should share the same way of new

Cpp Chapter 9: Memory Models and Namespaces Part2

9.2.4 Static duration, external linkage ) External variables External variables are defined outside, thus external to any function.It is also termed global variables, which could be accessed in any function that follow's the external variable's defin

Cpp Chapter 12: Classes and Dynamic Memory Allocation Part1

12.1 Dynamic memory and classes 12.1.1 A review example and static class members Now try implement a String class(a flawed one): // strngbad.h -- flawed string class definition #include <iostream> #ifndef STRNGBAD_H_INCLUDED #define STRNGBAD_H_INCLU

[AWDwR4] chapter 11 Play time 2th: use blind_up effect

chapter 11 Play time Play time 2:    使用Script.aculo.us JavaScript库中的blind_up效果代替隐藏cart这个div的过程.    上网搜了一下,jquery中有blind这个效果,所以就用jquery中的hide("blind"),而不使用Script.aculo.us JavaScript库    app/views/carts/destroy.js.erb这个文件可以有好几种写法,对照着可以加深理解:      

Chapter 11.预写式日志(Write-Ahead Logging (WAL)

11.1. 一般性描述 预写式日志 (WAL) 是一种实现事务日志的标准方法.有关它的详细描述可以在 大多数(如果不是全部的话)有关事务处理的书中找到. 简而言之,WAL 的中心思想是对数据文件 的修改(它们是表和索引的载体)必须是只能发生在这些修改已经 记录了日志之后 -- 也就是说,在日志记录冲刷到永久存储器之后. 如果我们遵循这个过程,那么我们就不需要在每次事务提交的时候 都把数据页冲刷到磁盘,因为我们知道在出现崩溃的情况下, 我们可以用日志来恢复数据库:任何尚未附加到数据页的记录 都将先

零元学Expression Blend 4 - Chapter 11 用实例了解布局容器系列-「Border」

原文:零元学Expression Blend 4 - Chapter 11 用实例了解布局容器系列-「Border」 将教大家以实做案例认识Blend 4 的布局容器,此章介绍的布局容器是Blend 4 里的专情王子-「Border」. ? ? 本系列将教大家以实做案例认识Blend 4 的布局容器,此章介绍的布局容器是Blend 4 里的专情王子-「Border」. ? ? 就是要让不会的新手都看的懂! ? <专情王子?查理B> Border是Blend里最简单的布局容器,可以使用Borde

Cpp Chapter 13: Class Inheritance Part1

class inheritance lets you derive new classes from old ones, inheriting its properties of the old class, called the base class With inheritance, you can: 1 add functionality to existing classes 2 add the data a class represents 3 modify how a class m

Cpp Chapter 9: Memory Models and Namespaces Part1

9.1 Separate compilation ) C++ could compile multiple files separately and link them into the final executable program ) You can divide original program into three parts(three files): 1. A header file that contains structure declarations and prototyp