初步了解类和对象

类和对象

定义一个类

class className 
{
	private:
	私有属性和函数
	public:
	公有属性和函数
	protected:
	保护属性和函数
};
  • 如果某个成员前面没有上述关键字,则缺省地被认为
    是私有成员
class Man 
{
	int nAge;        // 私有成员
	char szName[20]; //  私有成员
	public:
		void SetName(char * szName)
		{
			strcpy( Man::szName,szName);
		}
};

类成员可被访问的范围

– private (私有成员):

  • 基类的成员函数
  • 基类的友元函数

– public (公有成员):

  • 可以在任何地方访问

– protected( 保护成员):

  • 基类的成员函数
  • 基类的友元函数
  • 派生类的成员函数可以访问当前对象的基类的保护成员
 在类的成员函数内部,能够访问:
 当前对象的全部属性、函数;
 同类其它对象的全部属性、函数。
 在类的成员函数以外的地方,只能够访问该类对象的
公有成员

成员函数的重载及参数缺省

  • 成员函数也可以重载
  • 成员函数可以带缺省参数
  • 使用缺省参数要注意避免有函数重载时的二义性
#include <iostream>
using namespace std;
class Location 
{
	private :
		int x, y;
	public:
		void init( int x=0 , int y = 0 );
		void valueX( int val ) 
		{ 
			x = val ;
		}
		int valueX() 
		{ 
			return x; 
		}
};
void Location::init( int X, int Y)
{
	x = X;
	y = Y;
}

int main() 
{
	Location A,B;
	A.init(5);
	A.valueX(5);
	cout << A.valueX();
	return 0;
}
输出:
5

构造函数

基本概念

  • 成员函数的一种
  • 名字与类名相同,可以有参数,不能有返回值(void也不行)
  • 作用是对对象进行初始化,如给成员变量赋初值
class Complex 
{
	private :
		double real, imag;
	public:
		Complex( double r, double i = 0);
};
Complex::Complex( double r, double i) 
{
	real = r; 
	imag = i;
}

Complex c1;                 // error, 缺少构造函数的参数
Complex * pc = new Complex; // error, 没有参数
Complex c1(2);              // OK
Complex c1(2,4), c2(3,5);
Complex * pc = new Complex(3,4);
  • 如果定义类时没写构造函数,则编译器生成一个默认的无参数的构造函数
  • 默认构造函数无参数,不做任何操作
  • 如果定义了构造函数,则编译器不生成默认的无参数的构造函数
class Complex 
{
	private :
	double real, imag;
	public:
	void Set( double r, double i);
};                             //编译器自动生成默认构造函数
Complex c1;                    //默认构造函数被调用
Complex * pc = new Complex;    //默认构造函数被调用
  • 对象生成时构造函数自动被调用。对象一旦生成,就再也不能在其上执行构造函数
  • 一个类可以有多个构造函数,参数个数或类型不同
class Complex 
{
	private :
		double real, imag;
	public:
		void Set( double r, double i );
		Complex(double r, double i );
		Complex (double r );
		Complex (Complex c1, Complex c2);
};
  • 构造函数最好是public的,private构造函数不能直接用来初始化对象

构造函数在数组中的使用

class Test 
{
	public:
		Test( int n) { }        //(1)
		Test( int n, int m) { } //(2)
		Test() { }              //(3)
};
Test array1[3] = { 1, Test(1,2) };
  • 三个元素分别用(1),(2),(3)初始化
Test array2[3] = { Test(2,3), Test(1,2) , 1};
  • 三个元素分别用(2),(2),(1)初始化
Test * pArray[3] = { new Test(4), new Test(1,2) };
  • 两个元素分别用(1),(2) 初始化

复制构造函数

基本概念

  • 只有一个参数,即对同类对象的引用。
  • 形如 X::X( X& )或X::X(const X &), 二者选一后者能以常量对象作为参数
  • 如果没有定义复制构造函数,那么编译器生成默认复制构造函数。默认的复制构造函数完成复制功能。
  • 如果定义的自己的复制构造函数,则默认的复制构造函数不存在。
  • 不允许有形如 X::X( X )的构造函数。
    例:
class Complex 
{
	public :
		double real,imag;
		Complex(){ }
		Complex( const Complex & c ) 
		{
			real = c.real;
			imag = c.imag;
			cout << “Copy Constructor called”;
		}
};
Complex c1;
Complex c2(c1);//调用自己定义的复制构造函数,输出 Copy Constructor called

复制构造函数起作用的三种情况

1、当用一个对象去初始化同类的另一个对象时。

Complex c2(c1);
Complex c2 = c1; //初始化语句,非赋值语句
  • 注意:对象间赋值并不导致复制构造函数被调用
CMyclass c1,c2;
c1.n = 5; 
c2 = c1;
没有调用复制构造函数

2、如果某函数有一个参数是类 A 的对象,那么该函数被调用时,类A的复制构造函数将被调用。

class A
{
	public:
		A() { };
		A( A & a) 
		{
			cout << "Copy constructor called" <<endl;
		}
};
void Func(A a1){ }    //函数的参数是类 A 的对象
int main()
{
	A a2;
	Func(a2);         //A的复制构造函数被调用    
	return 0;
}
程序输出结果为: Copy constructor called

3、如果函数的返回值是类A的对象时,则函数返回时,A的复制构造函数被调用

class A
{
	public:
	int v;
	A(int n) { v = n; };
	A( const A & a) {
	v = a.v;
	cout << "Copy constructor called" <<endl;
	}
};

A Func()               //函数的返回值是类A的对象
{
	A b(4);
	return b;
}
int main() 
{
	cout << Func().v << endl;  //函数返回时,A的复制构造函数被调用
	return 0;
}
输出结果:
Copy constructor called
4

类型转换构造函数

  • 定义转换构造函数的目的是实现类型的自动转换。
  • 只有一个参数,而且不是复制构造函数的构造函数,一般就可以看作是转换构造函数。
  • 当需要的时候,编译系统会自动调用转换构造函数,建立一个无名的临时对象(或临时变量)。

例:

  • 隐式类型转换构造函数
class Complex 
{
	public:
		double real, imag;
		Complex( int i)      // 类型转换构造函数
		{
			cout << "IntConstructor called" << endl;
			real = i; imag = 0;
		}
		Complex(double r,double i) {real = r; imag = i; }
};
int main ()
{
	Complex c1(7,8);
	Complex c2 = 12;		//调用类型转换构造函数
	c1 = 9;                	// 9 被自动转换成一个临时Complex 对象
	cout << c1.real << "," << c1.imag << endl;
	return 0;
}
  • 显式类型转换构造函数,必须显式调用
class Complex 
{
	public:
		double real, imag;
		explicit Complex( int i) //显式类型转换构造函数
		{
			cout << "IntConstructor called" << endl;
			real = i; imag = 0;
		}
		Complex(double r,double i) {real = r; imag = i; }
};
int main () 
{
	Complex c1(7,8);
	Complex c2 = Complex(12);
	c1 = 9; // error, 9不能被自动转换成一个临时Complex对象
	c1 = Complex(9) //ok
	cout << c1.real << "," << c1.imag << endl;
	return 0;
}

析构函数

基本概念

  • 名字与类名相同,在前面加‘~’, 没有参数和返回值,一个类最多只能有一个析构函数。
  • 析构函数对象消亡时即自动被调用。可以定义析构函数来在对象消亡前做善后工作,比如释放分配的空间等。
  • 如果定义类时没写析构函数,则编译器生成缺省析构函数。缺省析构函数什么也不做。
  • 如果定义了析构函数,则编译器不生成缺省析构函数。

调用情况

1、对象数组生命期结束时,对象数组的每个元素的析构函数都会被调用

class Ctest 
{
	public:
		~Ctest() { cout<< "destructor called" << endl; }
};
int main () 
{
	Ctest array[2];
	cout << "End Main" << endl;
	return 0;
}
输出:
End Main
destructor called
destructor called

2、delete 运算导致析构函数调用。

Ctest * pTest;
pTest = new Ctest; // 构造函数调用
delete pTest; // 析构函数调用
---------------------------------------------------------
pTest = new Ctest[3]; // 构造函数调用3次 次
delete [] pTest; // 析构函数调用3次

3、参数对象消亡也会导致析构函数被调用

4、函数调用的返回值(临时对象)被用过后,该临时对象析构函数被调用

class CMyclass 
{
	public:
		~CMyclass() { cout << "destructor" << endl; }
};
CMyclass obj;
CMyclass fun(CMyclass sobj )          // 参数对象消亡会导致析构函数被调用
{ 
	return sobj;                     // 函数调用返回时生成临时对象返回
}
int main()
{
	obj = fun(obj); // 函数调用的返回值(临时对象)被用过后,该临时对象析构函数被调用
	return 0; 
}

输出:
destructor
destructor
destructor

例:

class Demo 
{
	int id;
	public:
		Demo(int i)  
		{
			id = i;
			cout << "id=" << id << " constructed" << endl;
		}
		~Demo() 
		{
			cout << "id=" << id << " destructed" << endl;
		}
};

Demo d1(1);             	//(1)构造函数被调用
void Func()
{
	static Demo d2(2);		//生成静态局部对象(8)构造函数被调用
	Demo d3(3);				//(9)构造函数被调用
	cout << "func" << endl; //(10)输出“func”
}							//函数调用结束后引发析构函数调用,但静态局部对象程序结束时才会消亡(11)非静态局部对象d3消亡
int main () 
{
	Demo d4(4);				//(2)构造函数被调用
	d4 = 6;					//(3)6被转换成一个临时对象 (4)临时对象执行完语句后消亡,引发析构函数调用
	cout << "main" << endl; //(5)输出main
	{ 
		Demo d5(5);			//生成一个局部对象(6)构造函数被调用
	}						//局部对象的生存周期到大括号结束,(7)析构函数被调用
	Func();					//调用函数
	cout << "main ends" << endl;  //(12)输出“main ends”
	return 0;
}							//程序结束(13)d4消亡(一般来说先构造的后消亡)(14)静态局部对象d2消亡(15)d1消亡
输出结果: :
id=1 constructed
id=4 constructed
id=6 constructed
id=6 destructed
main
id=5 constructed
id=5 destructed
id=2 constructed
id=3 constructed
func
id=3 destructed
main ends
id=6 destructed
id=2 destructed
id=1 destructed
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值