// chapter-7.cpp : 定义控制台应用程序的入口点。
//
#include "stdafx.h"
#include<iostream>
#include<string>
#include<vector>
using namespace std;
class Sales_data //第一个访问说明符之前的成员属性由class和struct决定,class默认private,struct默认public
{
// 定义友元,外部函数可以访问非共有成员(protected,private)
friend Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
friend ostream &print(ostream &os, Sales_data &item); //声明为其友元函数,可以访问非共有成员。(友元声明并不是一个完整意义的函数声明!)
friend istream &read(istream &is, Sales_data &item);
public: //都可访问
//构造函数
Sales_data() = default; //只有当类没有声明任何构造函数时,才会自动生成默认构造函数
Sales_data(const string &s) :bookNo(s) {};
Sales_data(const string &s, unsigned n, double p) :bookNo(s), units_sold(n), revenue(p*n) {};
Sales_data(istream &);
string isbn() const { return bookNo; }; //默认使用this,等价于this->bookNo;使用const改变this指针为指向常量(底层const)的常量指针(this默认为常量指针(顶层const)),提高函数的灵活性!指向常量的常量指针函数,才可以使常量对象调用普通成员函数!此函数有前提条件,在函数体内不会改变this所指向的对象!
Sales_data &combine(const Sales_data&);
double avg_price() const;
//protected: //外部不可访问,继承可以访问!
private: //外部和继承不可访问,使用封装有2个重要的好处:1、确保用户不会无意间破坏封装对象;2、被封住的类具体实现细节可以随时修改,而无须调整用户级别的代码。
string bookNo;
unsigned units_sold = 0;
double revenue = 0.0;
};
//Sales_data非成员接口函数
Sales_data add(const Sales_data &lhs, const Sales_data &rhs);
ostream &print(ostream &os, Sales_data &item); //函数声明时候,形参等必须相同!
istream &read(istream &is, Sales_data &item);
double Sales_data::avg_price()const
{
if (units_sold)
return revenue / units_sold;
else
{
return 0;
}
}
Sales_data& Sales_data::combine(const Sales_data &rhs)
{
units_sold += rhs.units_sold;
revenue += rhs.revenue;
return *this; //返回调用该函数的对象。
}
istream &read(istream &is, Sales_data &item)
{
double price = 0;
is >> item.bookNo >> item.units_sold >> price;
item.revenue = price*item.units_sold;
return is;
}
//Sales_data(istream &)构造函数
Sales_data::Sales_data(istream &is)
{
read(is, *this);
}
ostream &print(ostream &os, Sales_data &item)
{
os << item.isbn() << " " << item.units_sold << " " << item.revenue << " " << item.avg_price();
return os;
}
Sales_data add(const Sales_data &lhs, const Sales_data &rhs)
{
Sales_data item = lhs;
item.combine(rhs);
return item;
}
class Screen
{
friend class window_mgr; //定义window_mgr为screen的友元类!,则window_mgr中的函数可以访问screen中的非公有成员!
//友元关系不存在传递关系,每个类定义自己的友元!
public:
using pos = string::size_type;
Screen() = default;
Screen(pos ht, pos wd, char c) :height(ht), width(wd), contents(ht*wd, c) {}
char get()const //隐式内联
{
return contents[cursor];
}
inline char get(pos ht, pos wd) const; //类内成员函数是自动的inline,也可以用inline直接声明内联函数。
Screen &move(pos r, pos c);
Screen &set(char c)
{
contents[cursor] = c;
return *this;
}
Screen &set(pos r, pos col, char ch) //返回*this对象的引用(即对象本身)
{
contents[r*width + col] = ch;
return *this;
}
Screen &displsy(ostream &os) //只能传入非常量版本,返回类型为非常量的引用!
{
do_display(os);
return *this;
}
const Screen &displsy(ostream &os) const //如果为const成员函数,则返回类型将是常量!????有什么问题没???
{
do_display(os);
return *this;
}
void some_member()const;
private:
pos cursor = 0;
pos height = 0, width = 0;
string contents;
mutable pos access_ctr = 0;
void do_display(ostream &os) const { os << contents; }
};
void Screen::some_member() const
{
++access_ctr; //变量声明为可变数据成员,即使在const成员函数,还是可以改变access_ctr的值!
}
inline Screen &Screen::move(pos r, pos c)
{
pos row = r*width;
cursor = row + c;
return *this;
}
char Screen::get(pos r, pos c) const
{
pos row = r*width;
return contents[row + c];
}
class window_mgr
{
public:
void clear(vector<Screen>::size_type i)
{
Screen &s = screens[i];
s.contents = string(s.height*s.width, ' ');
}
private:
vector<Screen> screens{ Screen(24,80,' ') }; //类作为类内数据成员时,初始化方法!
};
class ConstRef
{
public:
ConstRef() = default;
ConstRef(int i):ii(i),ci(i),ri(i){} //引用和const必须初始化!建议养成构造函数初始化的习惯!
private:
int ii;
const int ci;
int &ri;
};
class Data
{
public:
//非委托构造函数
Data(string s,string::size_type i,double p):item(s),cnt(i),price(p){}
//委托构造函数
Data():Data(" ",0,0){}
Data(string s):Data(s,0,0){}
Data(istream &is) :Data() { is >> item; }
private:
string item;
string::size_type cnt=0;
double price=0.0;
};
//聚合类,所有成员都是public,没有定义任何构造函数,没有类内初始值,没有基类也没有virtual函数!使用花括号进行成员初始化
struct Data
{
int ival;
string s;
}
Data val9={0,"Anna"};
int main()
{
Sales_data s1(cin); //使用构造函数Sales_data(istream &)创建对象
Screen myscreen(5, 3,' ');
const Screen myscreen_const(5,3,' '); //常量screen对象。
myscreen.set('#').displsy(cout);
cout << endl;
myscreen_const.displsy(cout); //调用常量版本函数
//Data obj1();
//Data obj2; 直接使用这种声明,定义一个默认初始化的对象!
cin.ignore();
return 0;
}
//类基本思想是数据抽象和封装。数据抽象依赖于接口和实现,接口包含用户所能执行的操作,实现包含类的数据成员、函数;封装实现了接口和实现的分离,用户只可以访问接口,而无法访问实现!
//类的定义分两步,1、编译成员声明;2、直到类全部可见后才编译函数体。
//类的构造函数,如果成员对象为const或者引用,则必须进行初始化!
//类的静态成员,所有类对象共用,可以通过对象、引用或者指针访问它~在类内声明,在类外定义!
//优秀的设计者应该关注那些有可能使用该类的程序员的需求,作为一个设计良好的类,既要有直观且易于使用的接口,也必须具备高效的实现过程!
const在函数形参,实参,返回类型的区别?
const int &i,常量引用形参!,在类内const成员函数为常量返回类型!(常量版本的函数),程序有必要同时定义一个非常量版本的函数!
网友评论