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;
    s.acquire("NanoSmart", 20, 12.5);
    s.show();
    s.buy(15, 18.125);
    s.show();
    s.sell(400, 20.00);
    s.show();
    s.buy(300000, 40.125);
    s.show();
    s.sell(300000, 0.125);
    s.show();
    return 0;
}

) The code below is a client:
client: a program that uses the class
server: the class declaration and the class methods


10.2.5 Changing the implementation

Output formatting features for cout:

avoid e-notation

std::ios_base::fmtflags orig = std::cout.setf(std::ios_base::fixed, ios_base::floatfield); // set the format while store original format in orig
...
std::cout.setf(orig, std::ios_base::floatfield) // reset to original format

set output precision

std::streamsize prec = std::cout.precision(3); // save preceding precision in prec
...
std::cout.precision(prec);

10.2.6 Reviewing our story to date

) Use member functions by applying membership operator(.) to objects: object.func();


10.3 Class Constructors and Destuctors

To accomplish initialization while declaration for class objects, C++ provides special member functions called class constructors. In fact, a constructor has no return type, its name is often same to the class's name. For example: constructor for class Stock is Stock()

10.3.1 Declaring and defining constructors

No return type, prototype goes in the public section:

// constructor prototype with default arguments
Stock(const string & co, long n = 0, double pr = 0.0);

Next comes the definition of the constructor in separate file:

Stock::Stock(const string & co, long n, double pr)
{
company = co;
if (n < 0)
{
    std::cerr << "Number of shares can't be negative; " << company << " shares set to 0.\n";
    shares = 0;
}
else
    shares = n;
share_val = pr;
set_tot();
}

) A program automatically invokes the constructor when it declares a object
) Parameters of the constructor should not share name with the member data.


10.3.2 Using constructors

There are explicit and implicit way to initialize objects with constructor:

Stock food = Stock("World Cabbage", 250, 1.25); // explicit
Stock garment("Furry Mason", 50, 2.5); // implicit

Whether calling the constructor function Stock() explicitly or use parentheses following an object's declaration are equivalent.


10.3.3 Default constructors

) If you don't provide any constructors, C++ automatically supplies a default constructor:

Stock::Stock() {}

When you initialize an object without initialization, you are just leaving all of its member data uninitialized:

Stock s; // values of s member data are uninitialized

) You could provide you own version of default constructor by 2 ways:
1 default arguments: set all arguments to be default arguments in the constructor:

Stock(const string & co = "Error", int n = 0, double pr = 0.0);

2 use function overloading to define a second constructor with no arguments:

Stock::Stock()
{
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

) If you have provided a nondefault constructor without providing a default one, declaration like this is an error:

Stock s; // not possible with current constructor

So it is usually correct to provide a default constructor with a nondefault one
) Examples of using constructors:

Stock first; // calls default constructor implicitly
Stock first = Stock(); // calls default constructor explicitly
Stock *prelief = new Stock; // calls default constructor implicitly
Stock first("Concrete Conglomerate"); // calls constructor
Stock second(); // !!! declares a function!!!
Stock third; // calls default constructor

When you implicitly call the default constructor, you don't use parentheses(difference between line 5 and line 6 in the code above)


10.3.4 Destructors

) A destructor is called automatically when a class object expires. A destructor has a special name: formed by the class name preceded by a tilde(~):

~Stock();

No return value, no declared type and no arguments for destructors.
) You have 2 ways of having a destructor:

  1. The compiler generates an implicit, do-nothing destructor.

  2. You provide definition for the destructor, no matter do-nothing type:

Stock::~Stock()
{
}

or do-something type:

Stock::~Stock()
{
    cout << "Bye,  " << company << "!\n";
}

10.3.5 Improving the stock class

) Major changes to the three files:
1 Adds constructors and destructors, removing unnecessary acquire() function
2 Format the output in Stock::show()
3 Refine the object-declaration syntax

void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. " << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    std::cout << "Company: " << company << "  Shares: " << shares << "\n";
    std::cout << "  Shares Price: $" << share_val << "  Total Worth: $" << total_val << "\n";
}
// stock10.cpp -- Stock class with constructors, destructor added
#include <iostream>
#include "stock10.h"

Stock::Stock()
{
    std::cout << "Default constructor called\n";
    company = "no name";
    shares = 0;
    share_val = 0.0;
    total_val = 0.0;
}

Stock::Stock(const std::string & co, long n, double pr)
{
    std::cout << "Constructor using " << co << " called\n";
    company = co;

    if (n < 0)
    {
        std::cout << "Number of shares can't be negative; " << company << " shares set to 0.\n";
        shares = 0;
    }
    else
        shares = n;
    share_val = pr;
    set_tot();
}

Stock::~Stock()
{
    std::cout << "Bye, " << company << "!\n";
}
void Stock::buy(long num, double price)
{
    if (num < 0)
    {
        std::cout << "Number of shares purchased can't be negative. " << "Transaction is aborted.\n";
    }
    else
    {
        shares += num;
        share_val = price;
        set_tot();
    }
}

void Stock::sell(long num, double price)
{
    using std::cout;
    if (num < 0)
    {
        cout << "Number of shares sold can't be negative. Transaction is aborted.\n";
    }
    else if (num > shares)
    {
        cout << "You can't sell more than you have! Transaction is aborted.\n";
    }
    else
    {
        shares -= num;
        share_val = price;
        set_tot();
    }
}

void Stock::update(double price)
{
    share_val = price;
    set_tot();
}

void Stock::show()
{
    using std::cout;
    using std::ios_base;
    ios_base::fmtflags orig = cout.setf(ios_base::fixed, ios_base::floatfield);
    std::streamsize prec = cout.precision(3);

    cout << "Company: " << company << "  Shares: " << shares << "\n";
    cout << "  Share price: $" << share_val;
    cout.precision(2);
    cout << "  Total Worth: $" << total_val << "\n";

    cout.setf(orig, ios_base::floatfield);
    cout.precision(prec);
}
// usestock1.cpp -- using the Stock class
// compile with stock10.cpp
#include <iostream>
#include "stock10.h"

int main()
{
    { // 1111111
        using std::cout;
        cout << "Using constructors to create new objects\n";
        Stock stock1("NanoSmart", 12, 20.0);
        stock1.show();
        Stock stock2 = Stock("Boffo Objects", 2, 2.0);
        stock2.show();

        cout << "Assigning stock1 to stock2:\n";
        stock2 = stock1;
        cout << "Listing stock1 and stock2:\n";
        stock1.show();
        stock2.show();

        cout << "Using a constructor to reset an object\n";
        stock1 = Stock("Nifty Foods", 10, 50.0);
        cout << "Revised stock1:\n";
        stock1.show();
        cout << "Done\n";
    } // 1111111
    return 0;
}

The result of the code:

) Noteworthy:
1 Extra braces were used(in usestok1.cpp where 1111111 occurs). In windowing environment, the window would close before the last two destructor calls, preventing you from seeing the last two "Bye, NanoSmart!" and "Bye, Nifty Foods!"
2 The following code:

Stock stock2 = Stock("Boffo Objects", 2, 2.0);

C++ actually has two ways to execute this: One is to let it behave like the following syntax:

Stock stock2("Boffo Objects", 2, 2.0);

The second is to create a temporary object which is then copied to stock2, which will cause the destructor call for temporary object. As a result, you will see output of "Bye, Boffo Objects" after the compiler calls the constructor, (which is kind of weird for me lol)
3 You could do object assignment:

stock2 = stock1;

4 Analyze following code:

stock1 = Stock("Nifty Foods", 10, 50.0);

stock1 already exists, so here the compiler create a temporary object of Stock which is later copied to stock1 to rewrite the contents of stock1. In this way, you could also use constructors to reassign objects.
5 In the output this could be observed:

Bye, NanoSmart!
Bye, Nifty Foods!

Remember that those automatic variables go on a stack which follows the principle of LIFO(last in first out), so the destructor is also called to delete them in the LIFO order
6 Choose initialization rather than assignment if possible(more efficient):

Stock stock2 = Stock("thing", 2, 2.0); // initialization invoked, doesn't create temporary objects
stock1 = Stock("thing2", 3, 2.0); // assignment invoked, create temporary objects

) You could also use list initialization with objects(those with braces):

Stock hot_tip = {"Derivatives Plus Plus", 100, 45.0};
Stock temp {};

const member functions

const Stock land = Stock("thing");
land.show();

The compiler would reject the second line because Stock::shoe() doesn't promise not to alter the data, where land is a const object. Solution is to place the const keyword after the function parentheses:

void show() const; // prototyp3
void stock::show() const // providing definition
{
    ...
}

Class functions declared and defined in this way are called const member functions.


10.4 Knowing your objects: the this pointer

) Consider defining a member function that looks at two Stock objects and return the reference to the larger of the two:

const Stock & topval(const Stock & s) const;

The first const says that it returns a reference to a const object, the second const shows that the argument object's value can't be altered, the third const promises that the function would not alter the data of the invoking object.
The function accesses one object implicitly(the invoking object) and one object explicitly(the argument object).
) A special pointer this is used to access the invoking object. The this pointer points to the object used to invoke a member function. To access the invoking object's members, use operator "->":

cout << this->total_val; // use -> to access data from pointer to structures or classes

When returning a reference to the invoking object, **return (*this)** as the invoking object. Complete definition of the comparison member function:

const Stock & Stock::topval(const Stock & s) const
{
    if (s.total_val > total_val)
        return s;
    else
        return *this;
}

Here comes revised version of class declaration and implementation files:

#ifndef STOCK20_H_INCLUDED
#define STOCK20_H_INCLUDED

#include <string>

class Stock
{
private:
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() {total_val = shares * share_val; }
public:
    Stock(); // default constructor
    Stock(const std::string & co, long n = 0, double pr = 0.0); // constructor
    ~Stock(); // destructor
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
    const Stock & topval(const Stock & s) const;
};

#endif // STOCK20_H_INCLUDED
#ifndef STOCK20_H_INCLUDED
#define STOCK20_H_INCLUDED

#include <string>

class Stock
{
private:
    std::string company;
    long shares;
    double share_val;
    double total_val;
    void set_tot() {total_val = shares * share_val; }
public:
    Stock(); // default constructor
    Stock(const std::string & co, long n = 0, double pr = 0.0); // constructor
    ~Stock(); // destructor
    void buy(long num, double price);
    void sell(long num, double price);
    void update(double price);
    void show();
    const Stock & topval(const Stock & s) const;
};

#endif // STOCK20_H_INCLUDED

猜你喜欢

转载自www.cnblogs.com/fsbblogs/p/9750738.html