C++一些注意点之类和对象

1.在说明一个类时,没有给出类体而给出类名时,属于类的引用性说明。引用性说明的类不能用来建立对象,只能用来说明函数的形参、指针和引用。例如:

class CC;
CC c1;//引用性说明不能用来建立对象
class X{
         CC c3,c4;//错误的
         CC* PC;//正确的,建立指针式可以的
....
};


2.定义一个类时,在类体中又包含了一个类的定义,称为类的嵌套。例如:

class outer{
public:
       class Inner{   //A
        public:
                 int x,y;
       };
       Inner c1,c2;   //B
       float a,b;     
}                     //C

     相对于类outer而言,类Inner是嵌套类。可以把嵌套类看做是一种成员类。系统并不为嵌套类分配内存空间。B行说明嵌套类的对象,在定义Outer类时,系统也不为嵌套类对象分配空间。只在定义Outer类的对象时,才为嵌套类的对象分配存储空间。嵌套类的作用域从其定义开始,到外层类的定义结束。Inner的作用到C行结束。


3.用对象的成员函数来访问该对象的成员时,在成员函数中,只要给出成员名就行了。但在成员函数外要访问对象中的一个成员,必须指明访问哪个一个对象的成员。

     在定义成员函数体时,均省略了this指针。指针类型应该是这样的:

                  classType *const this;//this指针不能被修改。

这个this指针一般不会用到,但是防止自身赋值中会用到:

                   void copy(classType  c)

                   {

                           if(&c!=this){.......}

                   }

 

4.在产生对象时,对象的数据成员进行初始化的方法有三种:(1)使用初始化列表,像结构体一样;(条件是成员必须是public)(2)使用构造函数进行初始化;(3)通过对象的复制构造函数进行初始化。

注1:在定义不带参数构造函数的对象,后面并没有括号。如果有括号,并不表示定义对象,更不表示调用不带参数            的构造函数,而是表示一个不带参数的函数,返回类型为classType。

                    classType  obj();//表示一个不太参数的函数声明,返回值为classType。

注2:在定义类时,若没有定义构造函数,则系统自动产生一个默认的空构造函数,什么也不干,即定义的对象的成            员变量的值为不确定的值。

注3:在定义类时,若定义了类的构造函数,则系统不产生缺省的构造函数。

注4:一个构造函数,没有参数或者所有参数都有默认值称为缺省的构造函数,一个类只能有一个缺省的构造函数。

注5:定义类时,类只是一个种导出的数据类型,并不为其分配空间,所以在定义数据成员不能初始化。(静态成员    除外,静态成员是在编译的时候静态分配内存的,而对象时动态分配内存的。静态成员必须要进行定义性说明,在定义性说明可以赋初值,如果不赋初值则取默认值)。

注6:类只定义了一种结构,类中的任意成员均不能使用关键字auto、extern或register限定其存储类型。


5.全局对象、静态对象和局部对象

void f()

{

        static classType  staticVar;//这句话只有在第一次调用的时候执行,创建了一个静态对象。

        classType  localVar;//这句话每次在调用f()的时候都执行。

}

classType  globalVar;//①这句话应该是首先被执行,在main函数之前执行。

int main()

{

        f();  //②执行这个函数,static classType  staticVar在这次调用执行。

        classType  localVar1;//③定义一个局部变量

        f();//④这次调用的时候,static classType  staticVar是不执行的。

}


6.new运算符

           可以使用new运算符来动态建立对象,用new关键字建立对象时,同样地也要自动调用构造函数,以便完成成员的初始化。具体步骤:

          (1)首先在堆内存中分配一个空间;

          (2)然后调用构造函数初始化对象的成员;

          (3)返回该动态对象的起始地址给栈空间的变量,使该变量指向堆内存的空间。

 例子:classType *ptr = new classType;//调用缺省的构造函数

            ...

            delete ptr;

         使用new运算符产生的动态对象,在不使用该对象时,必须用delete运算符来释放对象所占用的存储空间。delete运算符删除一个new出来的对象时,步骤:(1)调用该对象的析构函数;(2)释放该对象所占用的内存空间。


7.析构函数的执行

例子1:

void main()

{

        classType  obj(50,100);

        obj.print();

        cout<<"退出主函数";

}

执行结果:

        50 100           //打印

        退出主函数;//先执行完主函数

        调用了析构函数;//在主函数执行完,遇到"}"才执行析构函数。


 例子2:

              全局对象:程序结束后调用析构函数;

          局部对象:退出作用域时,调用析构函数;

          静态对象:程序结束后调用析构函数;

          new出来的动态对象:delete调用时,才调用析构函数。

#include<iostream>
#include<string>

using namespace std;

class classType{
private:
	string str;
public:
	classType(string str)
	{
		this->str = str;
		cout<<str<<"调用构造函数"<<endl;
	}

	~classType()
	{
		cout<<str<<"调用析构函数"<<endl;
	}
};

classType globalVar("全局对象");
int main()
{
    cout<<"进入主函数"<<endl;
	classType localVar1("局部对象1");
	if(1){
        classType localVar2("局部对象2");
	}
	static classType staticVar("静态对象");
	cout<<"退出主函数"<<endl;
	return 0;
}


执行结果这样的:



例子3:

void main()

{

classType *ptr=new classType[2];

        delete []ptr;

        delete ptr;//②

        cout<<"退出主函数"<<endl;

}

执行结果:

        调用析构函数;//执行析构函数打印这句话

        调用析构函数;//析构函数其实执行了2次,换成②语句执行一次

        退出主函数;


注1:没定义析构函数时,系统产生缺省的空的析构函数,什么也不执行。在对象中有”new出来的东西“需要定义析构函数,因为在系统撤销对象时,系统自动回收为对象分配的空间,但是不自动回收”new出来的的东西“。

注2:析构函数内终止程序执行时,不能调用exit,但可以使用abort,因为exit又调用了析构函数,形成递归调用,不行。



8.构造函数的执行

例子1:

#include<iostream>
#include<string>

using namespace std;

class classType{
private:
	int num;
public:
	classType(int num)
	{
		this->num = num;
		cout<<num<<"调用构造函数"<<endl;
	}

	~classType()
	{
		cout<<num<<"调用析构函数"<<endl;
	}
};


int main()
{
        classType x1(50);
	classType x2=100;
	x2 = 200;
	cout<<"退出主函数"<<endl;
	return 0;
}

执行结果:


说明:(1)当函数只有一个参数时,classType x1=100 等价于classType x1(100),当构造函数只有一个参数的时候且没有explicit关键字时,该语句不会调用复制构造函数,阿里巴巴的笔试又做错了,警醒。就是本博客:http://blog.csdn.net/lsjseu/article/details/9708093,还是有些错误,事实说话。

           (2)x2=200等价于x2=classType(200)编译器会首先生生成一个临时变量,并将该对象赋值给x2,完成赋值后,撤销临时变量,即调用析构函数。当构造函数有多个参数时必须通过构造函数强制转换。

                    x3 = classType(50,100);//假设有两个参数。


例子2:

void main()

{

        classType t1;

        classType t2 = t1;//调用复制构造函数

        classType t2 (t1);//调用复制构造函数

}


例子3:

void main()

{

classType  x = classType(50,100);//调用了两次构造函数,一次是生成临时对象,二次是赋值构造函数

}


例子4:

#include<iostream>
#include<string>

using namespace std;

class obj{
private:
	int num;
public:
	obj(int num)
	{
		this->num = num;
		cout<<num<<"调用obj的构造函数"<<endl;
	}

	~obj()
	{
		cout<<num<<"调用obj的析构函数"<<endl;
	}
};

class con{
private:
	obj one,two;
	int data;
public:
	con(int i,int j,int k):two(i+j),one(k)
	{
		data = i;
		cout<<data<<"调用con的构造函数"<<endl;
	}

	~con()
	{
		cout<<data<<"调用con的析构函数"<<endl;
	}
};

int main()
{
    con c(100,200,400);
	return 0;
}
运行结果:

注1:编译器会自动生成复制构造函数

                classType(classType &t){num = t.num;}

但是当有类中有“new出来的东西”时,就必须自己定义构造函数。因为有new出来的东西,这样赋值就是两个对象的指针指向了同一个空间。在释放的时候,会调用析构函数。造成第一对象调用析构函数释放了空间,第二个对象又调用析构函数去释放,造成错误。

注2:对对象成员的构造函数先调用类对象的构造函数,再调用自身的构造函数。其调用顺序取决于对象成员在类中的声明顺序有关,而跟初始化列表中的顺序无关。

注3:C++默认会产生构造函数、析构函数、拷贝函数和赋值函数。


待续。。。。


  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值