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


转载于:https://www.cnblogs.com/fsbblogs/p/9770762.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值