类和对象
1.类是对象的抽象,对象是类的实例化。结构体里面只有数据成员,类里面有数据成员和成员函数。
类所定义的是一个标准,不分配内存空间
2.访问属性,public,protected,private
3.函数声明时有分号,定义的格式如下:
(1) 将成员函数在类外定义的一般形式是:
返回类型 类名∷成员函数名(参数表)
{
// 函数体
}
(2) 将成员函数以内联函数的形式进
行说明。在C++中,可以用下面两种格式
将成员函数声明为类的内联函数:
a.隐式声明 直接将函数声明在类外部
b.显式声明内联函数
这种成员函数在类外定义的一般形式是:
inline 返回类型 类名::成员函数名(参数表)
{
// 函数体
}
内联函数作用:以空间换时间,提高运行速度
4.成员函数的重载(返回值类型不作为重载标志),(函数名相同,参数类型,个数不同),类名相同的成员函数才能成为重载成员函数
5.对象的定义(与结构体类似)
(1)在声明类的同时,直接定义对象,即在声明类的右花
括号“}”后,直接写出属于该类的对象名表。
(2)声明了类之后,在使用时再定义对象,定义的
格式与一般变量的定义格式相同
6.对象成员的访问:
通过成员运算符“.”访问
通过对象的指针访问“”
int main()
{
student stu,*p;
p=&stu;
p->set(2);
(*p).get();
}
通过对象的引用变量访问对象中的数据成员
例题:定义一个point类
要求:
数据成员:x,y
成员函数:
设置x的值、设置y的值,获取x的值,获取y的值
计算两个点之间的距离
编写主函数进行测试
#include <iostream>
#include <cmath>
using namespace std;
class Point{
int x,y;
public:
void setx(int x) { this->x=x; }
void sety(int y) { this->y=y; }
int getx() { return x; }
int gety() { return y; }
double distance(Point p2) {return sqrt((x-p2.x)*(x-p2.x)+(y-p2.y)*(y-p2.y));}
};
int main(){
int x1,y1,x2,y2;
Point p1,p2;
cout<<"Please input Point1:"; cin>>x1>>y1;
cout<<"Please input Point2:"; cin>>x2>>y2;
p1.setx(x1); p1.sety(y1); p2.setx(x2); p2.sety(y2);
cout<<p1.distance(p2)<<endl; cout<<p2.distance(p1)<<endl;
return 0;
}
7.this指针
需要显式引用this指针的三种情况
(1)在类的非静态成员函数中返回类对象本身或对
象的引用的时候,直接使用 return *this,返回本
对象的地址时,return this。
(2)当参数与成员变量名相同时,如this->x = x,
不能写成x = x。
(3)避免对同一对象进行赋值操作,判断两个对象
是否相同时,使用this指针
void add(int i)与void add(int i,A*const this),每个函数都有this指针,会隐藏不写。
8.构造函数
(1)定义格式
类名::类名([参数表])
{
函数语句
}
(若显式的定义构造函数,系统默认的无参构造会消失)
(2)利用构造函数创建对象有两种格式
a. 利用构造函数直接创建对象.其一般形式为:
类名 对象名[(实参表)];
这里的“类名”与构造函数名相同,“实
参表”是为构造函数提供的实际参数。
b.利用构造函数创建对象时,通过指针和new来实现。其一般语法形式为:
类名 *指针变量 = new 类名[(实参表)];
例如:
Date *date1=new Date(1998,4,28);
就创建了对象(*date1)
例:
void main()
{
Date *date1;
date1=new Date(1998,4,28);
// 以上两条语句可合写成:Date *date1=new Date(1998,4,28);
cout<<"Date1 output1:"<<endl;
date1showDate();
date1 setDate(2002,11,14);
cout<<"Date1 output2:"<<endl;
date1 showDate();
delete date1; }
(3).必须使用参数初始化列表对数据成员进行初始化的几种情况
• 数据成员为常量
• 数据成员为引用类型
• 数据成员为没有无参构造函数的类的对象
按照数据成员在类中的声明顺序进行初始化,与初
始化成员列表中出现的顺序无关
(4)构造函数的重载(定义了全部带默认值的构造函数,不能再定义无参构造函数)
(带默认值的构造函数相当于多个构造函数)
9.析构函数
析构函数自动调用(隐式调用)
析构函数没有返回值,不能有参数,也不能重载,一个类只能定义一个析构函数
定义格式如下:
类名::~类名()
{
函数语句
}
默认析构函数形式如下:
类名::~类名(){}
必须定义析构函数的情况:
但如果类的数据成员中包含指针变量是从堆上进行存储空
间分配的话,需要在析构函数中进行存储空间的回收
10.复制构造函数
复制构造函数名与类名相同,并且也没有返回值类型。
复制构造函数可写在类中,也可以写在类外。
复制构造函数有且仅有一个参数,即是同类对象的引用。
如果没有显式定义复制构造函数,系统自动生成一个默认形式的复制构造函数
定义格式:
class 类名
{
public:
类名(参数表); //构造函数
类名([const] 类名 &对象名); //复制构造函数
┇ };
类名::类名([const] 类名 &对象名) {
函数语句
}
以下三种情况下由编译系统自动调用复制构造:
a.声明语句中用类的一个已知对象初始化该类的另一个对象时。
b.当对象作为一个函数实参传递给函数的形参时,需要将实参
对象去初始化形参对象时,需要调用复制构造函数。
c.当对象是函数的返回值时,由于需要生成一个临时对象作为
函数返回结果,系统需要将临时对象的值初始化另一个对象,
需要调用复制构造函数。
浅复制与深复制:
在用一个对象初始化另一个对象时,只复制了数据成员,而没有复制资源,使两个对象同时指向了同一资源的复制方式称为浅复制。
默认复制构造函数所进行的是简单数据复制,即浅复制
通过一个对象初始化另一个对象时,不仅复制了数据成员,也复制了资源的复制方式称为深复制。
缺省复制构造函数所进行的复制是浅复制。
当成员变量中含有指针变量时,需要定义深复制构造函数
深复制构造函数示例
Person::Person(const Person& P0) //复制构造函数的实现
{
name=new char[strlen(P0.name)+1];
strcpy(name,P0.name);
age=P0.age;
salary=P0.salary;
}
10.静态成员:(只被初始化一次,生命期长)
静态成员提供了同一个类不同对象数据成员的共享机制
例如:
static int total;
static void display();
静态成员函数可以直接访问该类的静态数据成员,而不
能直接访问非静态数据成员。
例:
#include<iostream>
#include<cstring>
using namespace std;
class Person
{
static int total;
static int Max_number;
public:
Person();
static void display()
{
cout<<"total="<<total<<endl;
cout<<"Max_number:"<<Max_number<<endl;
}
void print_no()
{
cout<<S_number<<endl;
}
private:
char *name;
int S_number;
};
Person::Person()
{
char name1[20];
cout<<"Please Input Staffer Name:";
cin>>name1;
name=new char[strlen(name1)+1];
strcpy(name,name1);
total++;
S_number=1000+total; //员工编号从1000开始
Max_number=S_number;
}
int Person::total=0;
int Person::Max_number=0;
void main()
{
Person s1;
Person s2;
Person s3;
Person s4;
Person::display(); //通过类名调用静态成员函数
s4.display(); //通过对象调用静态成员函数
s3.print_no(); //输出第3位员工的个人编号
}
11.友元
若需要在类的外部直接访问类的私有数据成员,在C++中,通过定义友元可以实现这一功能
友元的作用:共享
性质:单向性、非传递性
格式:friend 返回值类型 函数名(参数表);
友元函数可以访问类中的私有数据成员,但友元函数不是类的成员函数;
友元函数可以是一个普通函数,也可以是另外一个类的成员函数;
友元类:若一个类被声明为另一个类的友元,则该类的所有成员函数都是另一个类的友元。
友元类的格式:friend class 类名;
12:常类型
常类型是指使用关键字const说明的类型,常类型的变量或对象成员的值在程序运行期间是不可改变的
常引用的说明形式如下:
const 类型说明符 &引用名;
常对象的说明格式
类名 const 对象名;或:
const 类名 对象名;
13,类的包含
类的包含(称为has A)是程序设计中一种软件重用技术。即定义一个新的类时,通过编译器把另一个类 “抄”进来。
//例6-23 简单对象成员初始化
#include<iostream>
using namespace std;
class A
{ public:
A(int x):a(x){ }
int a ;
};
class B
{ public:
B( int x, int y ) : aa(x) { b = y ; }
void out() { cout<<"aa = "<<aa.a<<endl<<"b = "<<b<<endl ; }
private:
int b ;
A aa ;
} ;
int main()
{ B objB( 3, 5 ) ;
objB.out() ;
}
题目整理:
一:
定义一个dog类,包含age、weight属性,以及对这些属性
的操作方法。实现并测试这个类。
复习时做的:
#include<iostream>
using namespace std;
class dog
{
private:
int age;
double weight;
public:
dog(){};
dog (int a,double w)
{
age=a;
weight=w;
}
void get()
{
cout<<"该小狗的年龄为:"<<age<<"体重为:"<<weight<<endl;
}
void reset()
{
cout<<"请输入小狗现在的年龄和体重"<<endl;
cin>>age>>weight;
}
};
int main()
{
dog d1(2,20.0);
d1.get();
d1.reset();
d1.get();
return 0;
}
学习时做的:
#include <iostream>
using namespace std;
class dog
{
private:
double age;
double weight;
public:
dog(){};
~dog(){}
dog(double m,double n):age(m),weight(n){};
void setage(double age);
void setweight(double weight);
double showage();
double showweight();
};
inline void dog::setage(double age)
{
this->age=age;
}
inline void dog::setweight(double weight)
{
this->weight=weight;
}
inline double dog::showage()
{
return age;
}
inline double dog::showweight()
{
return weight;
}
int main()
{
double m,n;
cin>>m>>n;
dog a,b(17,20);
a.setage(m);
a.setweight(n);
cout<<"before:"<<endl;
cout<<a.showage()<<" "<<a.showweight()<<endl;
cout<<"now:";
cout<<b.showage()<<" "<<b.showweight()<<endl;
}
感觉之前做的好麻烦,应该是为了把学的东西都用一下吧(还是现在退步厉害)
二:
设计并测试一个名为Rectangle 的矩形类,其属性为矩形
的左下角与右上角两个点的坐标,能计算矩形的面积。
现在的:
#include <iostream>
using namespace std;
class Rectangle
{
private:
double x1,y1,x2,y2;
public:
Rectangle (){};
Rectangle (double a,double b,double c,double d)
{
x1=a;y1=b;
x2=c;y2=d;
}
void setleftdown()
{
cout<<"输入矩形左下角坐标"<<endl;
cin>>x1>>y1;
}
void setrightup()
{
cout<<"输入矩形右上角坐标"<<endl;
cin>>x2>>y2;
}
void area()
{
double x,y;
x=x2-x1;
y=y2-y1;
cout<<1.0*x*y<<endl;
}
} ;
int main()
{
Rectangle a(1,2,2,4);
a.area();
Rectangle b;
b.setleftdown();
b.setrightup();
b.area();
return 0;
}
之前的:
#include <iostream>
using namespace std;
class cube
{
private:
double x1,y1,x2,y2;
public:
cube();
~cube();
cube(double a,double b,double c,double d);
void setleftup();
void setrightdown();
void showleftup();
void showrightdown();
double lalculatedarea();
};
inline cube::cube()
{}
inline cube::~cube()
{}
inline void cube::setleftup()
{
cout<<"输入矩形左上角坐标"<<endl;
cin>>x1>>y1;
}
inline void cube::setrightdown()
{
cout<<"输入矩形右下角坐标"<<endl;
cin>>x2>>y2;
}
double cube::lalculatedarea()
{
double x=x1-x2,y=y1-y2;
return x*y;
}
int main()
{
cube a;
a.setleftup();
a.setrightdown();
cout<<a.lalculatedarea()<<endl;
}
三:
创建一个Student类,该类中具有学生姓名,学号,性别,
年龄,三科成绩、平均成绩等数据成员。在该类中定义成
员函数实现相关信息的输入、输出。函数的原型声明放在
类定义中。实现并测试这个类。
A:
#include <iostream>
#include<cstring>
using namespace std;
class student
{
private:
char *name;
char *num;
char sex;
int age;
double score1,score2,score3;
double avescore;
public:
student(){};
student(char* name1,char* num1,double ag,char s,double a,double b,double c)
{
name=new char[strlen(name1)+1];
strcpy(name,name1);
num=new char[strlen(num1+1)+1];
strcpy(num,num1);
sex=s;
age=ag;
score1=a;score2=b;score3=c;
}
~student(){};
void setinformation()
{
cin>>name>>num>>age>>sex>>score1>>score2>>score3;
}
void showinformation()
{
cout<<"姓名:"<<name<<endl;
cout<<" 学号:"<<num<<endl;
cout<<" 年龄:"<<age<<endl;
cout<<" 性别:"<<sex<<endl;
cout<<" 学科1分数:"<<score1<<" 2:"<<score2<<" 3:"<<score3<<endl;
cout<<" 三科平均成绩:"<<avescore<<endl;
}
void ave()
{
avescore=(score1+score2+score3)/3.0;
}
};
int main()
{
student n("zhang","123",18,'m',100,98,97);
n.ave();
n.showinformation();
return 0;
}
B;
#include <iostream>
#include <cstring>
using namespace std;
class student
{
private:
string name,number;
double score1,score2,score3,age,ave;
char genger;
public:
student(){};
student(string name,string number,double a,double b,double c,double age,char x);
void setinformation();
void showinformation();
void ff();
};
student::student(string name,string number,double a,double b,double c,double age,char x)
{
this->name=name,(*this).number=number,score1=a,score2=b,score3=c,this->age=age,genger=x;
}
void student::setinformation()
{
cin>>name>>number>>score1>>score2>>score3>>age>>genger;
}
void student::showinformation()
{
cout<<"姓名:"<<name<<endl;
cout<<" 学号:"<<number<<endl;
cout<<" 学科1分数:"<<score1<<" 2:"<<score2<<" 3:"<<score3<<endl;
cout<<" 三科平均成绩:"<<ave<<endl;
cout<<" 年龄:"<<age<<endl;
cout<<" 性别:"<<genger<<endl;
}
void student::ff()
{
ave=(score1+score2+score3)/3;
}
int main()
{
student m;
cout<<"请输入姓名 学号 学科1分数 学科2分数 学科3分数 年龄 性别"<<endl;
m.setinformation();
m.ff();
m.showinformation();
}
四:
(1)定义一个point 类
数据成员:点的坐标x,y
成员函数:带默认值的构造函数、set函数(设置x,y的值)、
输出x,y
(2)定义一个line类
数据成员:线上的两个点point1,point2(用定义好的point类)
成员函数:定义一条直线、计算线段的长度
(3)创建主函数,测试以上内容
#include <iostream>
#include<cmath>
#include<iomanip>
using namespace std;
class point {
public:
double x, y;
public:
point(double x = 0.0, double y = 0.0) : x(x), y(y) {}
~point() {}
void set(double a,double b)
{
this->x=a;
this->y=b;
}
double getX() { return x; }
double getY() { return y; }
};
class line
{
private :
point a,b;
public:
void setline(point m,point n)
{
this->a=m;
this->b=n;
}
void show()
{
cout<<"所求直线为("<<a.getX()<<","<<a.getY()<<")to("<<b.getX()<<","<<b.getY()<<")"<<endl;
}
double setdis()
{
double q=(a.x-b.x)*(a.x-b.x);
double w=(a.y-b.y)*(a.y-b.y);
double l=q+w;
double h=sqrt(l);
return h;
}
};
int main()
{
point class1,class2;
line line1;
class1.set(3,4);
class1.getX();
class1.getY();
class2.set(0,0);
class2.getX();
class2.getY();
line1.setline(class1,class2);
line1.show();
double m=line1.setdis();
cout<<"线段长度为"<<m<<endl;
return 0;
}
用类包含求计算两点之间的距离
#include<cmath>
#include<iostream>
using namespace std;
class Point
{ public:
Point( int xi=0, int yi=0 ) { x = xi; y = yi; }
int GetX() { return x; }
int GetY() { return y; }
private: int x; int y;
};
class Distance
{ public:
Distance( Point xp1, Point xp2 );
double GetDis() { return dist; }
private:
Point p1, p2; //Point类数据成员
double dist; //记录距离的数据成员
};
Distance::Distance( Point xp1, Point xp2 ) : p1( xp1 ), p2( xp2 )
{ double x = double(p1.GetX() - p2.GetX());
double y = double(p1.GetY() - p2.GetY());
dist = sqrt(x * x + y * y);
}
int main()
{ Point mp1( 5, 10 ), mp2( 20, 30 ) ;
Distance mdist( mp1, mp2 ) ;
cout<<"The distance is "<<mdist.GetDis()<<endl;
}
五:
创建一个Student类,该类中具有学生姓名(采用字符指针),学号,性别,年龄,三科成绩、平均成绩等数据成员。在该类中定义成员函数实现相关信息的输入、输出、平均成绩计算。
要求:
1、显式定义构造函数、析构函数、复制构造函数
2、创建主函数实现并测试这个类。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
class Student
{
char *name;
int num;
char a;//性别
int age;
double score1,score2,score3;
double ave;
public:
Student(){};
Student(const Student &p);
void set();
void show()
{
cout<<"姓名:"<<name<<endl;
cout<<" 学号:"<<num<<endl;
cout<<" 学科1分数:"<<score1<<" 2:"<<score2<<" 3:"<<score3<<endl;
cout<<" 三科平均成绩:"<<ave<<endl;
cout<<" 年龄:"<<age<<endl;
cout<<" 性别:"<<a<<endl;
}
void countave()
{
ave=(score1+score2+score3)/3.0;
}
~Student()
{
cout<<"Destructor"<<endl;
delete[] name;
}
};
void Student::set()
{
char name1[30],aa;
int n1,n2;
double ac1,ac2,ac3;
cin>>name1>>n1>>aa>>n2>>ac1>>ac2>>ac3;
name=new char[strlen(name1)+1];
strcpy(name,name1);
num=n1,a=aa,age=n2,score1=ac1,score2=ac2,score3=ac3;
}
Student::Student(const Student &p)
{
cout<<"copy"<<endl;
name=new char[strlen(p.name)+1];
strcpy(name,p.name);
num=p.num,a=p.a,age=p.age,score1=p.score1,score2=p.score2,score3=p.score3,ave=p.ave;
}
int main()
{
cout<<"请输入姓名 学号 学科1分数 学科2分数 学科3分数 年龄 性别"<<endl;
Student T1;
T1.countave();
T1.set();
T1.show();
Student T2(T1);//因为平均成绩要计算所以没有一开始检测复制构造,计算完后把所有信息一次性copy过去;
T2.show();
return 0;
}