1.抽象和类
首先知道oop方法首先从用户的角度考虑对象,即描述对象所需的数据以及描述用户与数据交互所需的操作。用户与数据交互的方式有三种:初始化、更新和报告,这也是用户接口。在c++中用户定义类型指的是实现抽象接口的类设计。类规范由两个方面组成,一个是类声明:以数据成员的方式描述数据部分,以成员函数(被称为方法)的方式描述公有接口。将数据和方法组合成一个单元是类最吸引人的地方。另一个是类方法定义:描述如何实现类成员函数。开发一个类有多个阶段:将接口(类定义)放在头文件中,并将实现(类方法的代码)放在源代码文件中。在定义中,简单的私有成员函数可以直接给出实现源代码。
访问和控制:只能通过公有成员函数(友元函数)来访问对象的私有成员。即公有成员函数(public)是程序和对象的私有成员之间的桥梁,提供了对象和程序之间的接口。关键字public表示组成类的公共接口的类成员(抽象),防止程序直接访问数据被称为数据隐藏。类设计尽可能将共有接口与实现细节分开。公有接口表示设计的抽象组件。将实现细节单独放在一起并将它们与抽象分开被称为封装。数据隐藏(将数据放在类的私有部分中)是一种封装。将实现细节隐藏在私有部分也是封装,以及将类函数的定义和类声明放在不同文件中也是封装。如果以后维护只需要修改实现细节,而无需修改程序接口。
通常程序猿使用私有成员函数来处理不属于公有接口的实现细节,且类对象的默认访问控制就是私有,即可省略private。如
class World
{
Float mass;
Char name[20];
Public:
Void tellall(void);
};
注意:在c++中,结构和类唯一区别是,结构的默认访问类型是public,而类为private。程序员通常使用类来实现类描述,而把结构限制为只表示纯粹的数据对象(POD)。
实现类成员函数:定义成员函数时候使用域解析运算符(::)来标识函数所属的类。类方法可以访问类的private组件。如
void Stock::update(doule price);stock意味着在实现代码中可以直接使用类私有成员以及私有成员函数。
注意当定义也在类声明中的函数自动变成内联函数,类声明常将短小的成员函数作为内联函数。如果愿意也可在类声明之外定义成员函数,并使其成为内联函数。只需在类实现部分中定义函数时使用inline限定符即可:
Class stock
{
Private:
Void set_tot();
Public:
…;
};
Inline void stock::set_tot()
{
Total_val=shares*share_val;
}
以上方法与直接在类声明中声明+定义的方式是等价的。最简便的做法是:将内联定义放在定义类的头文件中,可避免在每一个文件中都添加对其的定义代码。
对象:Stock kate,joe;是两个类对象,kat.show();joe.show();意味着调用kate对象的show()成员,也意味着show()方法将shares解释为kata.shares,每个新对象都有自己的存储空间,用于存储其内部变量和类成员,但同一个类的所有对象共享同一组类方法,即每种方法只有一个副本。即kate.shares 和joe.shares占据不同的内存块,但是kate.show()和 joe.show()都调用同一个方法。
2.类的构造函数和析构函数
类应该像基本类型int等一样可以初始化变量或者对象,如果只是跟之前使用公有成员函数来赋值私有数据成员那么就不能实现常规的初始化语法。为此c++引入一个特殊的成员函数---类构造函数将值赋给新对象的数据成员。名称与类名相同,没有返回类型但没有被声明为void类型。
声明和定义构造函数:在上面示例添加构造函数
Stock::Stock(const string co,long n=0,double pr=0.0);应将这句添加到原型的公有部分。然后定义代码使用域作用符在其他地方实现。程序在声明对象时将自动调用构造函数,即自动获得初始化。另外,构造函数的参数名不能与类成员相同。可以在数据成员名称中使用前缀或者后缀加以区分。
使用构造函数:
显示调用:Stock::food=Stock(“world cabbage”,250,1.25);
隐式调用:Stock::garment(“furry mason”,50,2.5);
使用new动态分配:Stock *pstock=new Stock(“ehg”,18,19.0);该句话将创建一个Stock对象将其初始化为参数提供的值,并将该对象的地址赋给pstock指针。无法使用对象来调用构造函数,因为在构造函数构造出对象之前,对象是不存在。
默认构造函数:在未提供显示初始值的时候,用来创建对象的构造函数。如
Stock fluffy_the_cat;如未提供任何构造函数,则c++将自动提供默认构造函数。它是默认构造函数的隐式版本,对Stock类来说可能如下:
Stock::Stock(){}因此将创建fluffy_the_cat对象但是不初始化它的成员值。类似int x;注意只有在没有定义任何构造函数的时候,编译器才会提供默认构造函数,一旦为类定义了构造函数后程序员就必须为它提供默认构造函数,仅当不接受任何参数的默认构造函数(这样才能声明未初始化的对象),如果提供非默认构造函数则不能声明一个未初始化的对象。
两种定义默认构造函数的方式:一种是给已有构造函数的所有参数提供默认值,如
Stock (const string & co=”error”,int n=0,double pr=0.0);
另一种方式是通过函数重载来定义另一个构造函数---一个没有参数的构造函数。
Stock();
只能有一个构造函数因此不要同时使用两种方式。用户定义的默认构造函数通常给所有成员提供隐式初始值。
Stock::Stock()
{
Company =”no name”;
Shares=0;
Share_val=0.0;
Total_val=0.0;
}
注意隐式的调用默认构造函数时不要使用圆括号。也不要被隐式调用非默认构造函数所误导。
析构函数:
构造函数创建对象后程序跟踪对象,直到其过期,程序将自动调用一个特殊的成员函数---析构函数。必须是在类名前+~,即~Stock(),析构函数没有参数,也可以没有返回值和类型。可以是
Stock::~Stock()
{
}
因为它不承担任何重要的工作。
如果创建的是静态存储类对象,则其析构函数将在程序结束时自动调用,如果创建的是自动存储类对象,则其析构函数将在程序执行完代码块时自动被调用。如果对象是被new创建的,则它将驻留在栈内存或者自由存储区中,当使用delete来释放内存时,其析构函数也将被调用。可以将一个对象赋给同类型的另一个对象,即把一个对象的成员复制给另一个。
Stock stock1(“haha”,12,20.0);将数据成员初始化为指定的值。
Stock stock2=Stock(“heheh”,2,2.0);有可能跟上面方式一样,也有可能创建一个临时对象,然后将该临时对象复制到stock2中并丢弃它。若再次使用这种方式,那么就不是初始化,肯定是将新值赋给它,即产生临时对象的方式。所以析构函数会出现,只不过出现的时间略有不同。
Main结束的时候,局部变量(类的对象)会消失,这种变量被放在栈中,因此最后创建的对象将最先被删除,最先创建的对象最后被删除。
C++11列表初始化:
允许提供与某个构造函数的参数列表匹配的内容,并用大括号将其括起来。
Stock hot_hip={“hahha”,100,45.0};
Stock jock{“heheh”};
Stock temp{};
前两个声明与函数提供的非默认构造函数相匹配,第三个声明与默认构造函数相匹配。
Const成员函数:
在类中,成员函数使用的对象是由方法调用隐式提供的,需要一种新的语法来保证函数不会修改调用对象。将const关键字放在括号的后面,show()应该像这样。
void show() const; 承诺不改变对象
void stock::show() const;函数的定义开头应该是这样
当成员函数不接受参数且想使用const,以这种方式声明和定义的类函数被称为const成员函数,就像应尽可能将const引用和指针用作函数形参一样,只要类方法不修改调用对象,就应该将其声明为const。
3.this指针
当使用一个类对象调用成员函数时,即将该对象隐式传递给函数内部,而当涉及两个对象的时候,则需要显示传递一个对象给函数参数,另一个对象用来调用因此隐式传递给函数。且引入this指针指向用来调用该方法的对象,*this就是该对象,这可以使得调用对象在函数内部出现。如
const Stock & Stock::topval(const Stock &s) const;
{
If(s.total_val>total_val)
Return s;
Else
Return *this;
}
Const Stock&代表着返回类型,括号里的const代表接受一个const Stock对象的引用,括号后面的const意味着该函数不会修改被隐式访问的对象。在函数中total_val 是this->total_val的简写,意味着这是调用对象的数据成员,*this是调用该函数的对象,相当于调用对象的别名。
4.对象数组
声明对象数组的方法与声明标准类型数组相同。
Stock::mystuff[4];声明一个包含数组包含着4个stock对象。前提是这个类要么没有任何显示定义的构造函数,要么自定义了一个显示默认构造函数。可以使用构造函数来初始化数组元素,必须为每个元素调用构造函数,并且允许使用不同的构造函数。
Const int stks=3;
Stock stock[stks]=
{
Stock(“hahah”,12.5,20),
Stock(),
Stock(“hehe”,130,3.25)
};
剩余的7个元素将采用默认构造函数进行初始化。
即初始化对象数组的方案是,首先使用默认构造函数创建数组元素,然后花括号中的构造函数将创建临时对象,然后将临时对象的内容复制到相应元素中,因此要创建类对象数组,这个类必须由默认构造函数。
注意:在调用成员函数时,如果使用了指针代替变量,使用指针+->代替点号来调用成员函数。
4.类作用域
类作用域:在类中定义的名称(如类数据成员名和类成员函数名)的作用域为整个类。只在该类已知,类外不可知。类作用域意味着不能从外部直接访问类的成员,共有函数也需要通过类对象调用。
只有在类声明或成员函数定义中可以使用未修饰的成员名称(不加::,未限定),其他情况下,使用类成员名时必须根据上下文使用直接成员运算符.,间接成员运算符(-)),或者作用域解析符号(::)。假设ik是个类,如
Ik *pik =new ik;
Ik ee=ik(8);
ee.viewik();
pik->viewik();
作用域为类的常量定义方式有两种,第一种是在类中声明一个枚举,在类声明中声明的枚举的作用域为整个类,因此可以用枚举为整型常量提供作用域为整个类的符号名称。
Class bakery
{
Private:
Enum{month=12};
Double costs[month];
}用这种枚举将不会创建类数据成员,所有对象中并不包含枚举。Month只是一个符号名称,在作用域为整个类的代码中,将用12来替换它。
另一种方式使用关键字static。
Class bakery
{
Private:
Static const int months=12;
Double costs[months];
}
作用域内枚举:传统枚举可能导致连个枚举定义中的枚举量发生冲突。C++11提供一种新枚举,其枚举量的作用域为类。如
Enum class egg{small ,medium,large,jumbo};
Enum class t_shirt{small,medium,large,xlarge};
使用时也应该采用枚举名来限定枚举量
egg choice=egg::large;
t_shirt floued=t_shirt::large;
并且c++11提高了作用域内枚举的类型安全,常规枚举可以自动转换为整型,但作用域内枚举不能隐式地转换为整型。不过也可以进行显示类型转换。
抽象数据类型(ADT):
栈存储了多个数据项,其次栈由可对它执行的操作来描述,如下
可创建空栈
可将数据项添加到堆顶(压入)
可从栈顶删除数据项(弹出)
可查看栈是否填满
可查看栈是否为空
//++++++++++++10_1.hpp++++++++++++++
#include<iostream>
#include<string>
using namespace std;
class Bankcount
{
private:
string names;
string counts;
double amounts;
public:
Bankcount(){string names="blank";string counts="blank";double amounts=0.0;}
Bankcount(const string & name,const string & count,double amounts=0.0);
~Bankcount(){cout<<"bye"<<endl;}
void show() const;
void save(double);
void take(double);
};
//++++++++++10_1.cpp++++++++++++++++++
#include<iostream>
#include"10_1.hpp"
Bankcount::Bankcount(const string & name,const string &count,double amount)
{
names=name;
counts=count;
amounts=amount;
}
void Bankcount::show() const
{
cout<<"your name is "<<names<<endl;
cout<<"your count is "<<counts<<endl;
cout<<"your money is "<<amounts<<endl;
}
void Bankcount::save(double cash)
{
amounts+=cash;
}
void Bankcount::take(double cash)
{
amounts-=cash;
}
//++++++++++++++++++10_1_main.cpp++++++++++++++++++++++++
#include<string>
#include"10_1.hpp"
int main()
{
Bankcount person;
person=Bankcount("dajidali","jinwanchiji",100);
person.show();
person.save(100);
person.show();
person.take(100);
person.show();
return 0;
}
//++++++++++++10_2.hpp++++++++++++++++++++++++++++
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
class Person
{
private:
static const int LIMIT=25;
string lname;
char fname[LIMIT];
public:
Person(){lname="";fname[0]='\0';}
Person(const string &ln,const char *fn="heyyou");
void show() const;
void formalshow() const;
};
//++++++++++++++++++10_2.cpp+++++++++++++++++++++++
#include<iostream>
#include"10_2.hpp"
Person::Person(const string &ln,const char *fn)
{
lname=ln;
strncpy(fname,fn,LIMIT-1);
fname[LIMIT-1]='\0';
}
void Person::show() const
{
cout<<fname<<" "<<lname<<endl;
}
void Person::formalshow() const
{
cout<<lname<<" "<<fname<<endl;
}
//++++++++++++++++++++10_2_main.cpp++++++++++++++++++++
#include<iostream>
#include"10_2.hpp"
int main()
{
Person one;
Person two("smythecraft");
Person three("Dimwiddy","sam");
one.show();
cout<<endl;
one.formalshow();
two.show();
two.formalshow();
three.show();
three.formalshow();
return 0;
}
//++++++++++++10_3.hpp+++++++++++++++++++++++++++++++++++++++++
#include<iostream>
#include<cstring>
using namespace std;
class Golf
{
private:
const static int LEN=20;
char fullname[LEN];
int handicap;
public:
Golf(){strcpy(fullname,"zhuzhu");handicap=0;}
Golf(const char *,int hc=0);
Golf setgolf();
void handi(int);
void showgolf() const;
};
//++++++++++++++++10_3.cpp+++++++++++++++++++++++++++++++++
#include<iostream>
#include"10_3.hpp"
int main()
{
Golf person1;
Golf person2=Golf("baobao",1);
Golf person3;
person3.setgolf();
person1.showgolf();
person2.showgolf();
person3.showgolf();
person1.handi(2);
person2.handi(2);
person3.handi(2);
person1.showgolf();
person2.showgolf();
person3.showgolf();
return 0;
}
//+++++++++++++++++++10_4.hpp++++++++++++++++++++++++++++++++
#include<iostream>
using std::cin;
using std::cout;
using std::endl;
namespace SALES
{
class Sales
{
private:
static const int QUARTERS=10;
double sales[QUARTERS];
double average;
double max;
double min;
public:
Sales(){double ar[1]={1};int n=1;}
Sales(const double ar[],int n=0);
void setsales();
void showsales() const;
};
}
//++++++++++++10_4.cpp+++++++++++++++++++++++++++++++++++
#include<iostream>
#include"10_4.hpp"
using namespace SALES;
Sales::Sales(const double ar[],int n)
{
double sum=0;
int i;
for(i=0;i<n;i++)
{
sales[i]=ar[i];
sum+=sales[i];
}
average=sum/n;
double temp_min=sales[i];
double temp_max=sales[i];
for(int j=1;j<n;j++)
{
if(temp_min>sales[j])
temp_min=sales[j];
if(temp_max<sales[j])
temp_max=sales[j];
}
max=temp_max;
min=temp_min;
}
void Sales::setsales()
{
int num;
cout<<"enter your numbers"<<endl;
cin>>num;
cin.get();
double val[num];
for(int k=0;k<num;k++)
{
cout<<"enter your information "<<k<<endl;
cin>>val[k];
cin.get();
}
*this=Sales(val,num);
}
void Sales::showsales() const
{
double limit=sizeof(sales)/sizeof(double);
for(int m=0;m<int(limit);m++)
{
cout<<"your sales"<<m<<" are "<<sales[m]<<endl;
}
cout<<"your average are "<<average<<endl;
cout<<"your max is "<<max<<endl;
cout<<"your min is "<<min<<endl;
}
//+++++++++++++++++++10_4_main.cpp+++++++++++++++++++++++++
#include<iostream>
#include"10_4.hpp"
using namespace SALES;
int main()
{
int number=4;
double arr[number]={1.0,2.0,3.0,4.0};
//using SALES::Sales;
Sales person1=Sales(arr,number);
Sales person2;
person1.showsales();
person2.setsales();
person2.showsales();
}
//+++++++++++++++10_5.hpp++++++++++++++++++++++++++++++++++
#include<iostream>
#include<cstring>
#include<cctype>
using namespace std;
struct customer
{
char fullname[35];
double payment;
};
typedef customer Item;
class Stack
{
private:
static const int MAX=10;
Item items[MAX];
int top;
public:
Stack();
bool isempty() const;
bool isfull() const;
bool push(const Item &item);
bool pop(Item & item);
};
//+++++++++++++10_5.cpp+++++++++++++++++++++++++++++++++++
#include<iostream>
#include<cstring>
#include"10_5.hpp"
Stack::Stack()
{
top=0;
}
bool Stack::isempty() const
{
return top==0;
}
bool Stack::isfull() const
{
return top==MAX;
}
bool Stack::push(const Item & item)
{
if(top<MAX)
{
strcpy(items[top++].fullname,item.fullname);
items[top-1].payment=item.payment;
top++;
return true;
}
else
return false;
}
bool Stack::pop(Item & item)
{
static double sum=0.0;
if(top>0)
{
strcpy(item.fullname,items[--top].fullname);
sum+=items[top].payment;
}
else
return false;
}
//++++++++++++++++++++++=10_5_main.cpp+++++++++++++++++++
#include<iostream>
#include"10_5.hpp"
#include<cctype>
#include<cstring>
int main()
{
using namespace std;
Stack st;
char ch;
customer po;
cout<<"enter your struct,\nP to precess a PO,or Q to quit."<<endl;
while(cin>>ch&&(ch=toupper(ch))!='Q')
{
cout<<"here"<<endl;
/*if(!isalpha(ch))
cout<<"is alpha";
continue;*/
switch(ch)
{
case 'A':
case 'a':cout<<"to add your fullname"<<endl;
cin.getline(po.fullname,35);
cin.get();
cin.get();
cout<<"to add your payment"<<endl;
cin>>po.payment;
cin.get();
if(st.isfull())
cout<<"stack already empty"<<endl;
else
st.push(po);
break;
case 'p':
case 'P':if(st.isempty())
cout<<"stack is already empty"<<endl;
else
{
st.pop(po);
cout<<po.fullname<<"poped"<<endl;
}
break;
}
}
cout<<"bye"<<endl;
return 0;
}
//++++++++++++++++10_6.hpp++++++++++++++++++++++
#include<iostream>
using namespace std;
class Move
{
private:
double x;
double y;
public:
Move(double a=0,double b=0);
void showmove() const;
void add(const Move &m);
void reset(double a=0,double b=0);
};
//++++++++++10_6.cpp++++++++++++++++++++++
#include<iostream>
#include"10_6.hpp"
Move::Move(double a,double b)
{
x=a;
y=b;
}
void Move::showmove() const
{
cout<<"your x is "<<x<<endl;
cout<<"your y is "<<y<<endl;
}
void Move::add(const Move &m)
{
x+=m.x;
y+=m.y;
}
void Move::reset(double a,double b)
{
x=a;
y=b;
}
//+++++++++10_6_main.cpp+++++++++++++++++
#include<iostream>
#include"10_6.hpp"
int main()
{
Move person1;
Move person2=Move(1,2);
person1.showmove();
person1.add(person2);
person1.showmove();
person1.reset(0,0);
person1.showmove();
}
//+++++++++++++10_7.hpp++++++++++++++++++++++++
#include<iostream>
#include<cstring>
using namespace std;
class Plorg
{
private:
char name[19];
int ci;
public:
Plorg(){strncpy(name,"Plorg",19);ci=50;}
Plorg(char *ar,int c=50);
void revise(Plorg &);
void show() const;
};
//++++++++++++++10_7.cpp+++++++++++++++++++++
#include<iostream>
#include"10_7.hpp"
Plorg::Plorg(char *ar,int c)
{
strncpy(name,ar,18);
name[19]='\0';
ci=c;
}
void Plorg::revise(Plorg &pl)
{
strncpy(name,pl.name,18);
name[19]='\0';
ci=pl.ci;
}
void Plorg::show() const
{
cout<<"your name is "<<name<<endl;
cout<<"your ci is "<<ci<<endl;
}
//+++++++++++++++10_7_main.cpp+++++++++++++++++
#include<iostream>
#include"10_7.hpp"
int main()
{
Plorg person1;
Plorg person2=Plorg("haha",20);
person1.show();
person2.show();
person1.revise(person2);
person1.show();
person2.show();
}
//++++++++++++++10_8++++++++++++++++++++++++++++
difficult...