20140413 拷贝、赋值构造 变量分配确定时期 子类指针与父类指针转化 虚函数

1、变量内存分配的时间问题

对于全局对象,静态对象以及分配在栈区域内的对象,对它们的内存分配是在编译阶段就完成了;而对于分配在堆区域内的对象,例如,new,它们的分配是在运行是动态进行的。

例子:int i=0;这句话还没有运行时,&i已经有地址了,这就是所谓的编译时就分配好内存

image

2、c++类创建对象

http://blog.csdn.net/gukesdo/article/details/7514080

分配空间->初始化->赋值

对象的初始化是通过初始化列表来完成。

对象的赋值是通过构造函数的实现体来完成的。

析构函数的作用就是销毁对象中的成员变量,在return 语句时或者作用域结束时使用。

3、拷贝构造函数与赋值构造函数(何时需要拷贝构造函数

http://blog.sina.com.cn/s/blog_60e96a410100lni7.html(拷贝构造函数和赋值函数--史上最全解释)

在 C++ 中,赋值和拷贝是不同的,

1)拷贝构造函数是对未初始化的内存进行初始化操作

  • 比如声明类对象时: 类A,A a=aa;(假设aa是已经初始化的类对象)
  • 函数形参为类对象时: 类A,fun(A a),掉用fun时就会进行形参的拷贝(注意:fun(A &a)是不会调用拷贝构造函数的)

2)而赋值是对现有的已经初始化的对象进行操作。(这里我对“已经初始化”的理解是已经调用了构造函数,并且构造函数体可以未执行,只要调用到即可)

  • 例如:类A,A a;  a=aa;(假设aa是已经初始化的类对象),此时会调用复制构造函数

3)重点:包含动态分配成员的类 应提供拷贝构造函数,并重载"="赋值操作符。(深拷贝)

4)可以说,C++中什么时候有临时对象产生,此时刻c++一定要调用拷贝构造函数。(临时对象产生时有一个特例,此时不需要调用拷贝构造函数,例如类A,A a=1000;)

#include <iostream>
using namespace std;
class B
{
public:
    B()
    {
        cout<<"default constructor"<<endl;
    }
    ~B()
    {
        cout<<"destructed"<<endl;
    }
    B(int i):data(i)   //B(int) works as a converter ( int -> instance of B)
    {
        cout<<"constructed by parameter " << data <<endl;
    }
    B & operator=(const B &other)
    {
        if(this == &other)
            return *this;
        data = other.data;
        cout<<"constructed by ="<<endl;
        return *this;
    }
    B(const B& other)    //拷贝构造函数
    {
        data = other.data;
        cout<<"constructed by copy"<<endl;
    }
private:
    int data;
};
B Play( B b)
{
    return b ;
}
int main(int argc, char* argv[])
{
    B t1 = Play(5); 
    B t2 = Play(t1);//先复制构造将t1复制给Play中的b,然后Play函数返回时,//再复制构造给t2.中间没有出现所谓的临时变量,至少从调试中观察变量data等的地址判断是这样
    return 0;
}

4、子类和父类指针的转化,虚函数p125

 
#include<iostream>
using namespace std;
class A
{
public:
    void virtual f()
    {
        cout<<"A"<<endl;
    }
};

class B :public A
{
public:
    void virtual f()
    {cout<<"B"<<endl;}
};

int main()
{
    A* pa=new A( );
    pa->f( );  //输出A
    B* pb=(B*)pa; //父指针pa强转化为子类指针必须有强制类型
    pb->f();//输出A
    pa=pb;//子指针pb转换为父类指针不需要强制类型
    pa->f(); //输出A
    delete pa,pb;
    pa=new B();
    //pb=(B*)new A();子指针赋给父类pb必须要有强制类型转化
    pa->f();//输出B
    pb=(B*)pa;//父指针pa转化为子类指针必须有强制类型
    pb->f();//输出B
}

5、形参是类的对象会引用拷贝构造函数,形参是引用不会调用构造函数

#include<iostream>
using namespace std;
class Animal
{
public:
    Animal(){}
    void eat(){cout<<"eat\n";}
    Animal(const Animal &a)
    {
        cout<<"constructed by copy"<<endl;
    }
};

class Cat: public Animal
{
public:
    Cat(){}
    void Meaw(){cout<<"meaw\n";}
    Cat(const Animal &a)
    {
        cout<<"constructed by copy"<<endl;
    }
};

void Func( Cat  an)//对象作为函数参数时调用拷贝构造函数
//void Func(Cat &an)引用做函数参数时只是传递地址,不会调用拷贝构造函数
{
    an.eat();
}
void main()
{
    Cat dao;
    Func(dao);
}
posted @ 2014-04-13 12:36  yexuannan  阅读(308)  评论(0编辑  收藏  举报