所有的对象都需要一个确定的初始状态。这样我们可以使用一个initialize函数来进行初始化。对象在建立后可以调用这个函数进行初始化。
initialize在这里只是一个普通的函数,必须进行调用,如果没有调用,对象的结果将是不确定的。
#include <stdio.h>
class A
{
private:
int a;
int b;
int c;
public:
void initialize()
{
a = 9;
b = 8;
c = 7;
}
int print()
{
printf ("a = %d\n", a);
printf ("b = %d\n", b);
printf ("c = %d\n", c);
return 0;
}
};
int main()
{
A b;
b.print();
return 0;
}
这里打印的三个值在VS2008的编译环境下是一样的,但是很明显都是垃圾值。
initialize这个函数只是C++中的一种初始化函数,个人感觉在类的封装以后应该没有使用这种形式的初始化了,因为要额外的调度一次初始化函数。
①构造函数是类成员函数,比较特殊的类成员函数
②构造函数的名字与类的名字相同
③构造函数在定义的时候可以有参数,但是没有任何返回类型的声明
对象的内存分配并不是由构造函数来完成的,对象的内存分配是由编译器来完成的,构造函数的作用是对对象本身进行初始化工作,也就是给用户提供初始化类中成员变量的一种方式。
基本例程如下:
#include <stdio.h>
class A
{
private:
int a;
int b;
int c;
public:
A(int d)
{
a = b = c = d;
}
int print()
{
printf ("a = %d, b = %d, c = %d\n",a, b, c);
return 0;
}
};
int main()
{
A b(1);
A c = 2;
b.print();
c.print();
}
这里构造函数初始化类的成员一共有两种形式,分别是
A b(1); A c =2;这两种形式都是自动调用构造函数。还有一种是手动调用构造函数的形式,
A b = A(9);
#include <stdio.h>
class A
{
private:
int a;
int b;
int c;
public:
A(int d)
{
a = b = c = d;
}
A()
{
a = b = c = 8;
}
int print()
{
printf ("a = %d, b = %d, c = %d\n",a, b, c);
return 0;
}
void print(int x)
{
printf("x = %d", x);
}
};
int main()
{
A b = A(9);
b.print();
return 0;
}
无参构造函数是构造函数没有参数,而拷贝构造函数是为了无参构造函数而生的。
例程如下:
#include <stdio.h>
class A
{
private:
int a;
int b;
int c;
public:
A()
{
printf (".....\n");
}
A (const A& i)
{
printf ("~~~~~\n");
}
void print(int x)
{
printf("x = %d", x);
}
};
int main()
{
A b1 ;
A b2 = b1;
return 0;
}
程序打印结果如下图所示:
当类中没有定义任何一个构造函数,C++编译器会为其提供无参构造函数和拷贝构造函数。当类中定义了任意的非拷贝构造函数的时候,C++编译器不会为其提供无参构造函数。
A()
{
int a;
printf (".....\n");
}
A (const A& i)
{
i.a = 2;
printf ("~~~~~\n");
}
上面的程序编译将会报错,因为变量a的作用域只在原函数的A()中,所以我们不能够进行调用,但是我们可以对A函数中的printf进行调用。具体的拷贝构造函数还是不太理解,而且有很多其他的要求,例如深拷贝和浅拷贝,还有继承类中的拷贝等等。
参考其他博客得到:
如果一个类中没有定义任何的构造函数,那么编译器只有在以下三种情况,才会提供默认的构造函数:
1、如果类有虚拟成员函数或者虚拟继承父类(即有虚拟基类)时;
2、如果类的基类有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数);
3、在类中的所有非静态的对象数据成员,它们对应的类中有构造函数(可以是用户定义的构造函数,或编译器提供的默认构造函数)。
#include <stdio.h>
class A
{
private:
int a;
int b;
int c;
public:
/*A()
{
//a = b = c = i;
}
A(const A& oj)
{
}*/
void print()
{
printf("a = %d\n", a);
printf("b = %d\n", b);
printf("c = %d\n", c);
}
};
int main()
{
A b;
A c = b;
b.print();
c.print();
return 0;
}
要求:创建一个数组类。
具体代码如下所示:
main.cpp
#include <stdio.h>
#include "a.h"
int main()
{
A a = 5;
for (int i = 0; i < a.getlength(); i++)
{
a.setdata(i,i);
printf ("%d\n",a.getdata(i));
}
A b = a;
for (int j = 0; j < b.getlength(); j++)
{
printf ("%d\n",b.getdata(j));
}
a.destroy();
b.destroy();
return 0;
}
a.cpp
#include "a.h"
A::A(int length)
{
if (length < 0) //进行安全性检测
{
alength = 0;
}
alength = length;
/*申请大小为alength个int类型的空间*/
ap = new int[alength];
}
/*这里不使用C++编译器给的默认的拷贝构造函数*/
A::A(const A& aj)
{
alength = aj.alength;
//重新从堆上进行空间分配
ap = new int[alength];
/*依次进行值得拷贝*/
for(int i=0; i<alength; i++)
{
ap[i] = aj.ap[i];
}
}
int A::getlength()
{
return alength; //直接返回数组的长度
}
void A::setdata(int index, int data)
{
ap[index] = data;
}
int A::getdata (int index)
{
return ap[index];
}
void A::destroy()
{
alength = -1; //将长度赋为-1,表示出错
delete []ap; //对申请的堆空间进行释放
}
a.h
#ifndef _A_H
#define _A_H
class A
{
private:
int alength;
int* ap;
public:
A(int length);
A(const A& aj);
int getlength();
void setdata(int index,int data);
int getdata (int index);
void destroy();
};
#endif
通过上面的a.cpp可以看出,这里没有使用默认的
C++拷贝构造函数,因为默认的C++拷贝构造函数只是进行简单的值复制,也就是将我们在
构造函数中的数组的大小和数组的指针进行复制,
经过拷贝构造函数的数组和原来的数组指向同一块内存空间,而我们在主函数中对同一块内存空间进行了两次delete,所以程序会崩溃。
解决办法是不使C++编译器默认的拷贝构造函数,在自己定义的拷贝构造函数中重新为第二个数组分配内存空间。