7、类的定义格式(续)
>在类体中不允许对所定义的数据成员进行初始化:
class TDate
{
public:
....
private:
int year(1998),month(4),day(9);
};
>类中的数据成员的类型可以是任意的:
1.包括整型、浮点型、数组、指针和引用等;
2.另一个类的对象,可以作为类的成员;
3.自身类的对象不可以作为该类的成员;
4.自身类的指针或引用可以作为该类的成员;
5.当另一个类的对象作为该类的成员时,如果另一个类的定义在后,需要提前说明;
6.一般在类体内先说明用户感兴趣的公有成员,再说明私有成员;
7.习惯将类定义的说明部分或整个定义部分(包含实现部分)放到一个头文件;
8、构造函数和析构函数:
》特殊的成员函数
》构造函数:在创建对象时,使用特定的值来将对象初始化;
》析构函数:用来释放对象,在对象删除前做一些清理工作;
9、拷贝初始化构造函数的三种情况:
a.明确表示由一个对象初始化另一个对象时;
例如:TPoint N(M);
b.当对象作为函数实参传递给函数形参时(传值调用);
例如:P=f(N);
c.当对象作为函数返回值时(数据值);
例如:return R;
#include<iostream.h>
#include"tpoint.h"
TPoint f(TPoint Q);
void main()
{
TPoint M(20,35),P(0,0);
TPoint N(M); //1.M参数传递给N时会打印出Copy_initialization Constructor called
P = f(N);
cout<<"P="<<P.Xcoord()<<","<<P.Ycoord()<<endl;//6.
//6.同时由于M对象的释放,将打印Destructor called.
//7.同时由于P对象的释放,将打印Destructor called.
//8.同时由于N对象的释放,将打印Destructor called.
}
TPoint f(TPoint Q) //2.N参数传递给Q时会打印出Copy_initialization Constructor called
{
cout<<"OK!"<<endl;//3.
int x,y;
x = Q.Xcoord() + 10;
y = Q.Ycoord() + 20;
TPoint R(x,y);
return R; //4.R参数传递给P时会打印出Copy_initialization Constructor called
//5.同时由于Q对象的释放,将打印Destructor called.
//6.同时由于R对象的释放,将打印Destructor called.
//7.匿名对象
}
/*
输出:
Copy_initialization Constructor called.
Copy_initialization Constructor called.
OK!
Copy_initialization Constructor called.
Destructor called.
Destructor called.
Destructor called. //匿名对象
P=30,55
Destructor called.
Destructor called.
Destructor called.
*/
10、赋值的构造:
Location &operator = (Location &p); //Location(Location &p)
Location & Location::operator = (Location& p)
{
X = p.X;
Y = p.Y;
cout<<"Asignment operator called."<<endl;
return *this; //返回this指针
}
补充:
当类中声明有指针数据成员时,必须定义拷贝初始化和赋值操作,否则编译器生成的
拷贝初始化操作和赋值操作的执行将导致程序在运行时产生问题;
class A A::A(int i)
{ {
public: p=new int(i);
A(int i); }
~A(); A::~A()
private: {
int *p; delete p;
}; }
void main()
{
A a(5);
A b(a); //运行过程中将会出现问题。原因在于b也有变量将指向5,释放将进行两个
//因此赋值操作要谨慎,特别出现了指针成员时,复制函数要另外书写。
A c(5),d(10);
d = c; //函数参数赋值 和 等式赋值一样将会造成两个指针指向同一个地方。
};
上述的程序明显不对,修改后有:
#include<iostream.h>
class A {
public:
A(int i); //构造函数
A(A &r); //重载构造函数
~A() ; //析构函数
A &operator=(A &r); //拷贝初始化构造函数中,传递的参数必须是类引用。
private:
int *p ;
};
//构造函数
A::A(int i)
{
this->p = new int(i); //给*p赋初始值
}
//拷贝初始化构造函数
A::A(A&r) //要使用别的A类的成员对另一个赋值,必须使用指针或引用!!!!
{
p = new int(*r.p); //1、new int(int i); 注意引用中的成员使用.(成员)来获取。
}
//析构函数
A::~A()
{
delete p;
}
//赋值操作函数
A & A::operator = (A &r)
{
if(this == &r) //如果r和this地址不同,那么返回this.
return *this;
cout<<"I am Here!!!!!!!!!"<<endl;
*p = *r.p; //2、引用要取出成员用.(成员)
return *this; //3、如果要将引用中指针成员取出,必须要将*加载*r.p前面
// 而不是r.(*p)。
}
void main()
{
A a(5);
A b(a); //运行过程中将会出现问题。原因在于b也有变量将指向5,释放将进行两个
//因此赋值操作要谨慎,特别出现了指针成员时,复制函数要另外书写。
A c(6),d(10); //重写与缺省:如果d不进行初值赋值,可能会出现构造函数重写的重叠,导致出错!!
d = c; //函数参数赋值 和 等式赋值一样将会造成两个指针指向同一个地方。
};
总结:1、new int(int i); 注意引用中的成员使用.(成员)来获取。
2、this指针取出成员用this->p,即->。
3、如果要将引用中指针成员取出,必须要将*加载*r.p前面而不是r.(*p)。
4、注意:
(1)A::A(A&r)该函数为拷贝初始化构造函数,实参参数为A &类型,在三种情况下调用:
a.明确表示由一个对象初始化另一个对象时;
例如:TPoint N(M);
b.当对象作为函数实参传递给函数形参时(传值调用);
例如:P=f(N);
c.当对象作为函数返回值时(数据值);
例如:return R;
(2)A & A::operator=(A &r)为赋值操作函数,实参和返回值为A &类型。
>在类体中不允许对所定义的数据成员进行初始化:
class TDate
{
public:
....
private:
int year(1998),month(4),day(9);
};
>类中的数据成员的类型可以是任意的:
1.包括整型、浮点型、数组、指针和引用等;
2.另一个类的对象,可以作为类的成员;
3.自身类的对象不可以作为该类的成员;
4.自身类的指针或引用可以作为该类的成员;
5.当另一个类的对象作为该类的成员时,如果另一个类的定义在后,需要提前说明;
6.一般在类体内先说明用户感兴趣的公有成员,再说明私有成员;
7.习惯将类定义的说明部分或整个定义部分(包含实现部分)放到一个头文件;
8、构造函数和析构函数:
》特殊的成员函数
》构造函数:在创建对象时,使用特定的值来将对象初始化;
》析构函数:用来释放对象,在对象删除前做一些清理工作;
9、拷贝初始化构造函数的三种情况:
a.明确表示由一个对象初始化另一个对象时;
例如:TPoint N(M);
b.当对象作为函数实参传递给函数形参时(传值调用);
例如:P=f(N);
c.当对象作为函数返回值时(数据值);
例如:return R;
#include<iostream.h>
#include"tpoint.h"
TPoint f(TPoint Q);
void main()
{
TPoint M(20,35),P(0,0);
TPoint N(M); //1.M参数传递给N时会打印出Copy_initialization Constructor called
P = f(N);
cout<<"P="<<P.Xcoord()<<","<<P.Ycoord()<<endl;//6.
//6.同时由于M对象的释放,将打印Destructor called.
//7.同时由于P对象的释放,将打印Destructor called.
//8.同时由于N对象的释放,将打印Destructor called.
}
TPoint f(TPoint Q) //2.N参数传递给Q时会打印出Copy_initialization Constructor called
{
cout<<"OK!"<<endl;//3.
int x,y;
x = Q.Xcoord() + 10;
y = Q.Ycoord() + 20;
TPoint R(x,y);
return R; //4.R参数传递给P时会打印出Copy_initialization Constructor called
//5.同时由于Q对象的释放,将打印Destructor called.
//6.同时由于R对象的释放,将打印Destructor called.
//7.匿名对象
}
/*
输出:
Copy_initialization Constructor called.
Copy_initialization Constructor called.
OK!
Copy_initialization Constructor called.
Destructor called.
Destructor called.
Destructor called. //匿名对象
P=30,55
Destructor called.
Destructor called.
Destructor called.
*/
10、赋值的构造:
Location &operator = (Location &p); //Location(Location &p)
Location & Location::operator = (Location& p)
{
X = p.X;
Y = p.Y;
cout<<"Asignment operator called."<<endl;
return *this; //返回this指针
}
补充:
当类中声明有指针数据成员时,必须定义拷贝初始化和赋值操作,否则编译器生成的
拷贝初始化操作和赋值操作的执行将导致程序在运行时产生问题;
class A A::A(int i)
{ {
public: p=new int(i);
A(int i); }
~A(); A::~A()
private: {
int *p; delete p;
}; }
void main()
{
A a(5);
A b(a); //运行过程中将会出现问题。原因在于b也有变量将指向5,释放将进行两个
//因此赋值操作要谨慎,特别出现了指针成员时,复制函数要另外书写。
A c(5),d(10);
d = c; //函数参数赋值 和 等式赋值一样将会造成两个指针指向同一个地方。
};
上述的程序明显不对,修改后有:
#include<iostream.h>
class A {
public:
A(int i); //构造函数
A(A &r); //重载构造函数
~A() ; //析构函数
A &operator=(A &r); //拷贝初始化构造函数中,传递的参数必须是类引用。
private:
int *p ;
};
//构造函数
A::A(int i)
{
this->p = new int(i); //给*p赋初始值
}
//拷贝初始化构造函数
A::A(A&r) //要使用别的A类的成员对另一个赋值,必须使用指针或引用!!!!
{
p = new int(*r.p); //1、new int(int i); 注意引用中的成员使用.(成员)来获取。
}
//析构函数
A::~A()
{
delete p;
}
//赋值操作函数
A & A::operator = (A &r)
{
if(this == &r) //如果r和this地址不同,那么返回this.
return *this;
cout<<"I am Here!!!!!!!!!"<<endl;
*p = *r.p; //2、引用要取出成员用.(成员)
return *this; //3、如果要将引用中指针成员取出,必须要将*加载*r.p前面
// 而不是r.(*p)。
}
void main()
{
A a(5);
A b(a); //运行过程中将会出现问题。原因在于b也有变量将指向5,释放将进行两个
//因此赋值操作要谨慎,特别出现了指针成员时,复制函数要另外书写。
A c(6),d(10); //重写与缺省:如果d不进行初值赋值,可能会出现构造函数重写的重叠,导致出错!!
d = c; //函数参数赋值 和 等式赋值一样将会造成两个指针指向同一个地方。
};
总结:1、new int(int i); 注意引用中的成员使用.(成员)来获取。
2、this指针取出成员用this->p,即->。
3、如果要将引用中指针成员取出,必须要将*加载*r.p前面而不是r.(*p)。
4、注意:
(1)A::A(A&r)该函数为拷贝初始化构造函数,实参参数为A &类型,在三种情况下调用:
a.明确表示由一个对象初始化另一个对象时;
例如:TPoint N(M);
b.当对象作为函数实参传递给函数形参时(传值调用);
例如:P=f(N);
c.当对象作为函数返回值时(数据值);
例如:return R;
(2)A & A::operator=(A &r)为赋值操作函数,实参和返回值为A &类型。