C++类学习(2)
Ⅰ:类概念
一:类的构成
class 类名
{
public:
公有数据成员和成员函数;类的接口
protected:
保护数据成员和成员函数;
private:
私有数据成员和成员函数;
};//注意一定不要忘记分号
对象和对象之间的关系:分别使用不同的内存来存储数据,使用相同的内存上的函数(一份函数拷贝)
二:创建类和使用类的基本流程
1.基本概念
类的声明和设计是最基础最重要的部分,合理的类声明可以让后面的工作很方便,也是面向对象思想的体现。
首先通过上面的结构图已经知道类的基本结构,首先就是数据,数据有公有和私有之分,这是权限。根据实际中的要求来决定数据的共有和私有属性。
然后就是函数。函数和数据其实是一样的。也有共有和私有之分。根据实际情况来确定是公有和私有。
class和struct定义的类稍有区别class的成员没有访问限定符(public,private,protected)时会默认成员为私有成员,struct会默认为公有成员
成员函数
在类外定义时要在函数名字前加类的名字和作用域符(::)来表示这个函数是在其所属的类作用域内。
在类内定义的成员函数默认为inline函数(内联函数)如果要在类外定义inline函数需要显式的在函数声明或定义前加关键字inline。成员函数也可以重载典型的如构造函数。
访问控制和封装
访问限定符
public:公有成员成员在任何函数或类中都可以被访问。
private:成员只能由类自己的成员函数或友元访问
protect访问权限介于public和prrivate之间。
2.构造函数
函数中有一个特殊的函数,那就是构造函数。因为一个类中大部分数据是隐藏的,总不能老是通过调用公共函数的方法来进行初始化。C++提供的就是构造函数的方法。
构造函数的建立规则是这样的。构造函数没有返回值,构造函数的名字和类的名字完全一模一样(大小写也相同),所有看到一个类声明中没有返回值,那么说明这个函数是构造函数,构造函数必须放在public下面。构造函数可以有很多种选择,这时候就需要用到函数重载的方法来定义了。
一般的构造函数声明为:
类名(){}
类名(参数表):初始化列表{函数体}
eg X(int a):r(a),g(a){h(a)};//初始化的时候是根据成员数据定义的顺序初始化
必须使用初始化的 引用成员 const类型的成员未提供默认构造函数的类类型其他的都可以在刚定义的时候赋予初值
一般最好写两个构造函数
默认构造函数:Student();
带有参数的构造函数:Student(参数列表);
注意:
在完全没有自已定义构造函数的时候,系统会提供一个默认构造函数,类似于Student(){}这个样子,仅仅创建一个对象但是不做任何初始化。也就是说,此时的一些数据成员都是没有被初始化的。
要是自己提供了构造函数,就必须自己同时为系统提供一个默认构造函数。
自己定义默认构造函数的方式有两种:定义一个没有参数的构造函数。给已有的构造函数的全部参数提供默认值。本质上,这两个构造函数使用的时候都不用加上任何参数。所以才能够做默认构造函数。
3.析构函数
构造函数起到了构造对象的作用,那么怎么销毁不需要用的对象呢。那就是析构函数。必须有一个析构函数若程序员没有提供析构函数,系统将自动提供一个默认的析构函数
析构函数定义方式:
1.原型:(~类名())
2.实现Student::
~Student()
{
函数体;
}
通常不在代码中显式的调用析构函数。
静态存储类对象(static):作用域为整个类,不随对象的消亡而消亡;
注意!!!!!!!不属于任何一个对象;
静态数据成员被当作类内的"全局变量";对非static数据成员每个对象都有一个自己的副本,而static数据成员则属于整个类并不在某个单独的对象中存在每个对象对它的操作都会使整体的static改变。
static数据成员对整个类类型只有一个由这个类型所有的对象共享访问。
初始化 static数据成员属于类,不属于某个特定对象因而不能再构造函数中初始化;所以需要在类定义之外初始化使用类名字限定但不需要重复用static限定(如果未初始化则编译器自动赋初值默认为0字符串默认为空)
4.类声明式样 (一个类为例)
class 类名{
数据成员;
public:
类名():初始化列表{
函数体;//可调用其他函数称为委托函数;
};//无参构造函数;
类名(参数):初始化列表{
函数体;
};//带参构造函数;
函数体;
}
1.自定义的构造函数创建对象(C++11的几种初始化方式统一起来了)
类名(参数)变量名;
2.自定义的默认构造函数创建对象
类名()变量名;
三:关于const成员函数
有时候,我们创建了一个对象,但是事实上,我们只希望这个对象初始化之后不被改变,它可以是一个真理或者是什么,就是不能被改变。 onst成员
const数据成员用来描述对象中的常量,只能在构造函数初始化列表中初始化并且一旦初始化就不能更改。
const函数 将一个成员函数声明为const表明这个成员函数不会修改对象的数据成员,能保证对象的常量性
声明形式:
返回类型 成员函数名(参数表) const;
定义形式:
返回类型 成员函数名(参数表)const{函数体}
const成员函数中不能修改类的数据成员,也不能调用其它非const成员函数(因为非const成员函数有可能会改变数据成员这样就会间接的改变数据成员导致编译出错)(ps const成员函数可以改变static成员的值)
只有声明为const的成员函数才可以被const对象调用,const对象不能调用非const成员函数,但是非const对象可以调用const成员函数(这个地方比较绕应该多看几遍加深理解!!!)
(psC++规定常对象只能调用它的常成员函数、静态成员函数、构造函数(具有公有访问权限)
如果一个成员函数是const的,则const对象可以调用它,非const对象也可以调用它,不会改变对象中的成员。
一定要强制养成在不改变类中的值得函数后加const的习惯!!使之成为const成员函数
四、this指针
每个成员函数都有一个隐含的参数,指向接收消息的对象称为this指针。
X类的this指针的类型是X*
this指针式一个常量含有当前对象的地址不能取它的值也不能改,常用于区分与局部变量重名的数据成员,返回当前对象,获取当前对象的地址。
访问器和修改器
因为对象的封装性private的成员函数无法直接访问于是就需要一种public函数来对他们进行访问和修改这就是访问器和修改器。
五、友元
让非成员函数访问一个类中的私有数据,需要在类中将这个函数声明为友元用friend关键字
友元必须在被访问的类中声明。一个类的友元可以是全局函数另一个类的成员函数或另一个类。
六:对象数组
当创建多个对象的时候,一个名字一个名字来写的话会很累。比如一个班上所有的人数。所以,这个时候用数组是一个很方便的选择。
创建格式:
1.创建且调用默认构造函数。
Student stu[100];
1
没错,就是这么简单(当然在底层,这些都是直接调用的默认的构造函数。)
2.创建调用自己写的构造函数初始化。
Student stu[100] =
{
Student(参数列表。。), //自定义构造函数初始化
Student(),//默认构造函数初始化
…
…
}
以两个程序来具体演示简单类的使用:
学生成绩管理系统:
#include <iostream>
#include <vector>
#include <map>
#include <string>
#include<algorithm>
using namespace std;
class student{
struct CJ{
string nam;
double grade;
double jd;
}ob;
vector<CJ> st;
double JD;
string name;
string xuehao;
string zy;
int nj,bj,pm;
public:
student():name("none"),zy("none"),xuehao("none"),nj(-1),bj(-1),pm(-1) {st.clear();}
void shuru(){
cout<<"请输入学生姓名:";
cin>>name;
cout<<"请输入学生学号:";
cin>>xuehao;
cout<<"请输入专业:";
cin>>zy;
cout<<"请输入班级(如2018-3)";
scanf("%d-%d",&nj,&bj);
cout<<"输入成绩(名称 成绩 学分)end 结束输入"<<endl;
while(true){
cin>>ob.nam;
if(ob.nam=="end"||ob.nam=="End"||ob.nam=="END") break;
cin>>ob.grade>>ob.jd;
st.push_back(ob);
}
}
/* bool cmp (student a,student b){
return a.JD>b.JD;
}*/
bool operator <(const student& d){
return JD<d.JD;
}
void jisuan(){
double sum=0,sum1=0,sum2=0;
for(auto i=st.begin();i!=st.end();i++){
sum=sum+i->jd;
if(i->grade>=60)
sum1=sum1+(i->grade/10-5)*i->jd;
}
JD=sum1/sum;
}
void print (){
cout<<"绩点"<<JD<<' '<<"姓名:"<<name<<' '<<"学号"<<xuehao<<' '<<"专业班级:"<<zy<<nj<<'-'<<bj<<' ';
for(auto i=st.begin();i!=st.end();i++){
cout<<i->nam<<' '<<i->grade<<' ';
}
cout<<endl;
}
/*
string getname(){
return name;
}
string gatxuehao(){
return xuehao;
}
string getzy(){
return zy;
}
int getpm(){
return pm;
}*/
};
student ob[40];
int n;
int main()
{
cout<<"请输入班级人数:";
cin>>n;
for(int i=0;i<n;i++){
ob[i].shuru();
ob[i].jisuan();
}
sort(ob,ob+n);
for(int i=0;i<n;i++) ob[i].print();
}
ATM:
#include <bits/stdc++.h>
using namespace std;
class Bankcard{
string account;
string owner;
int key;
double balance;
public:
Bankcard() :account("00000000000"),owner("Administrator"),key(123456),balance(0.1){};
Bankcard(string a,string o,int k,double b):account(a),owner(o),key(k),balance(b){};
void withdraw(int mo,int k){
if(Verification(k)) {
if(mo%100!=0) cout<<"Go to bank Counter"<<endl;
else balance=balance-mo;
}
else cout<<"Wrong password"<<endl;
}
void withdraw(double mo,int k){
if(Verification(k)) {
balance=balance-mo;
}
else cout<<"Wrong password";
}
void save(int mo,int k){
if(Verification(k)) {
if(mo%100!=0) cout<<"Go to bank Counter"<<endl;
else balance=balance+mo;
}
else cout<<"Wrong password"<<endl;
}
/* void opac(string a,string o,int k,double b){
account=a;
owner=o;
key=k;
balance=b;
}*/
void destroyac(){
withdraw(balance,key);
account="";
owner="";
key=0;
balance=0.0;
}
bool Verification(int k){
return k==key;
}
string const getow(){
return owner;
}
string const getac(){
return account;
}
double const getba(){
return balance;
}
void modify(int k){
int newkey;
if(Verification(k)) {
cin>>newkey;
key=newkey;
}
else cout<<"Wrong password";
}
~Bankcard(){
destroyac();
}
};
int main()
{
int withmo,putmo;
string ac,ow;
int key;
double bal;
cin>>ac>>ow>>key>>bal;
Bankcard ob(ac,ow,key,bal);
/*cout<<ob.getow()<<endl;
cout<<ob.getba()<<endl;
cout<<ob.getac()<<endl;*/
cin>>withmo>>key;
ob.withdraw (withmo,key);
// cout<<ob.getba()<<endl;
cin>>putmo>>key;
ob.save(putmo,key);
cout<<ob.getow()<<endl;
cout<<ob.getba()<<endl;
cout<<ob.getac()<<endl;
cin>>key;
ob.modify(key);
ob.destroyac();
return 0;
}