C++类和对象中构造函数和对象的初始化

无参构造函数,有参构造函数,拷贝构造函数:
int main()
{
{
//Test t1();
Test t1; // 无参构造函数调用
t1.print();
}
// 有参构造函数调用
{
//1 括号法
Test t1(1);
t1.print();
Test t2(1,2);
t2.print();

    //2 等号法
    Test t3 = 5;      // 只能进行简单的单个元素赋值
    Test t4 = (5,6);

    //3 直接调用构造函数
    Test t5 = Test(8,9);
    t5.print();
}

return 0;

}
对象初始化和赋值的不同:
Test t1(4,5);
Test t2 = Test(5,6); // 对象的初始化
t2 = t1; // 对象的赋值

拷贝构造函数调用时机:
1、Test t2 = t1; // 用对象 t1 去初始化t2
2、Test t2(t0); // 用对象 t0 去初始化t2
3、PrintObj(t0); // 做函数参数的时候
4、t1 = test(); // 函数返回值返回对象
实例代码:
#include
#include <string.h>

using namespace std;

class Test
{
public:
Test() // 无参构造函数
{
m_a = 0;
m_b = 0;
cout << “无参构造函数调用” << endl;
}

Test(int a)
{
    m_a = 1;
    m_b = 2;
    cout << "有参构造函数调用1" << endl;
}

Test(int a, int b)   // 有参构造函数
{
    m_a = a;
    m_b = b;
    cout << "有参构造函数调用2" << endl;
}

Test (char *name)
{
    strcpy(m_name, name);
}

// 赋值构造函数(拷贝构造函数)
Test(const Test &obj)
{
    cout << "拷贝构造函数调用" << endl;
    m_a = obj.m_a + 100;
    m_b = obj.m_b + 100;
    strcpy(m_name, "hello");
}

~Test()
{
    cout << "析构函数调用: " << m_name << endl;
}

public:
void print()
{
cout << “m_a:” << m_a << endl;
cout << “m_b:” << m_b << endl;
}
private:
char m_name[20];
int m_a;
int m_b;
};

void PrintObj(Test obj)
{
obj.print();
}

Test test()
{
Test A(“name A”);
return A;
}

// 赋值构造函数 用一个对象去初始化另一个对象
int main()
{
#if 0
Test t0 = Test(3,4);
Test t1 = Test(5,6);

{
    //1 拷贝构造函数调用 1
    Test t2 = t1; // 用对象 t1 去初始化t2
    t2.print();
}

{
    //2  拷贝构造函数调用 2
    Test t2(t0); // 用对象 t0 去初始化t2
    t2.print();
}

{
    //3 类对象当函数形参的时候,实参到形参的转换会调用拷贝构造函数
    PrintObj(t0);
}

#endif
{
//4 当函数的返回值是类对象的时候,用一个对象去接收后会调用拷贝构造函数
test();

    // 用匿名对象初始化 t, 此时c++编译器直接将匿名对象转化成 t (从匿名转成有名字)
    //Test t = test();

    Test t1("name t1");
    // 用匿名对象给其他对象进行赋值,复制完对象后匿名对象会被析构
    t1 = test();
    t1.print();

}
return 0;

}
浅拷贝与深拷贝:
解决浅拷贝的方案:
#include
#include <string.h>

using namespace std;

class Name
{
public:
Name(const char *p)
{
m_len = strlen§;
m_p = (char *)malloc(m_len + 1);
}

// 解决浅拷贝的方案:手动编写拷贝构造函数,进行深拷贝
Name (const Name &obj)
{
    m_len = obj.m_len;
    m_p = (char *)malloc(m_len + 1);
    strcpy (m_p, obj.m_p);
}

~Name()
{
    cout << "析构函数被调用" << endl;
    if (m_p != NULL)
    {
        free (m_p);
        m_p = NULL;
        m_len = 0;
    }
    cout << "析构函数执行结束" << endl;
}

private:
char *m_p;
int m_len;
};

int main()
{
{
Name name1(“xiaoming”);
Name name2 = name1;
}

return 0;

}
对象初始化列表:
1.必须这样做:
如果我们有一个类成员,它本身是一个类或者是一个结构,而且这个成员它只有一个带参数的构造函数,没有默认构造函数。这时要对这个类成员进行初始化,就必须调用这个类成员的带参数的构造函数,
如果没有初始化列表,那么他将无法完成第一步,就会报错。

2、类成员中若有const修饰,必须在对象初始化的时候,给const int m 赋值
当类成员中含有一个const对象时,或者是一个引用时,他们也必须要通过成员初始化列表进行初始化,
因为这两种对象要在声明后马上初始化,而在构造函数中,做的是对他们的赋值,这样是不被允许的。
2)C++中提供初始化列表对成员变量进行初始化
语法规则
Constructor::Contructor() : m1(v1), m2(v1,v2), m3(v3)
{
// some other assignment operation
}
3)注意概念
初始化:被初始化的对象正在创建
赋值:被赋值的对象已经存在

4)注意:
成员变量的初始化顺序与声明的顺序相关,与在初始化列表中的顺序无关
初始化列表先于构造函数的函数体执行

new和delete用法:
虽然为了与C语言兼容,C++仍保留malloc和free函数,但建议用户不用malloc和free函数,而用new和delete运算符。new运算符的例子:
new int; //开辟一个存放整数的存储空间,返回一个指向该存储空间的地址(即指针)
new int(100); //开辟一个存放整数的空间,并指定该整数的初值为100,返回一个指向该存储空间的地址
new char[10]; //开辟一个存放字符数组(包括10个元素)的空间,返回首元素的地址
new int[5][4]; //开辟一个存放二维整型数组(大小为5
4)的空间,返回首元素的地址
float p=new float (3.14159); //开辟一个存放单精度数的空间,并指定该实数的初值为//3.14159,将返回的该空间的地址赋给指针变量p

用new分配数组空间时不能指定初值。如果由于内存不足等原因而无法正常分配空间,则new会返回一个空指针NULL,用户可以根据该指针的值判断分配空间是否成功。
在执行new运算时,如果内存量不足,无法开辟所需的内存空间,目前大多数C++编译系统都使new返回一个0指针值。只要检测返回值是否为0,就可判断分配内存是否成功。

#include
using namespace std;

// 1、new 和 delete 与 malloc 和 free 的区别
// new 和 delete 是C++的操作符,用来动态申请和释放堆空间,是C++的语法
// malloc和free是C语言用来申请和释放堆空间的操作,但它们不是C语言的语法,是由标准库提供的函数

// 2、new 可以用来申请 基础类型 分配数组变量 分配类对象

// 分配基础类型
int main1()
{
// 申请基础数据类型
int *p = (int *)malloc(sizeof(int));

// 语法 : new 数据类型
int *p2 = new int;
*p2 = 30;

// new 可以在申请空间的同时对空间进行初始化
int *p3 = new int(40);
printf ("%d\n", *p3);

// 空间释放
free(p);
delete p2;
delete p3;

return 0;

}

// 分配数组类型:new 数据类型[N]
int main2()
{
// C语言分配数组
int *p = (int *)malloc(sizeof(int)*10); // int array[10]
p[0] = 1;
free§;

// C++分配数组
int *p1 = new int[10];
p1[2] = 30;

// C++释放申请的数组,要注意有方括号 [] 漏掉的话会造成内存泄露
delete[]  p1;

return 0;

}

class Test
{
public:
Test(int a)
{
m_a = a;
cout << “构造函数被调用” << endl;
}

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

private:
int m_a;
};

// 分配类对象
// new 会自动调用类的构造函数,delete会自动调用类的析构函数
int main()
{
// 用C方法
{
Test *p = (Test *)malloc(sizeof(Test));
free§;
}

// 用C++方法
{
    Test *p = new Test(3);
    delete p;
}

return 0;

}

静态成员变量:
关键字 static 可以用于说明一个类的成员,
静态成员提供了一个同类对象的共享机制
把一个类的成员说明为 static 时,这个类无论有多少个对象被创建,这些对象共享这个 static 成员
静态成员局部于类,它不是对象成员,在类的外部进行初始化
#include

using namespace std;

class Test
{
public:
Test(int a, int b)
{
m_a = a;
m_b = b;
}
public:
int m_a;
int m_b;
static int m_c; // 定义一个静态的类成员,该成员是所有类对象共享的
};

// 静态成员必须在类的外部进行初始化
int Test::m_c = 10;

int main()
{
Test a1(2,3);
Test a2(3,4);
Test a3(11,12);

// 静态成员可以直接通过对象进行访问,访问方式和其他成员方式一样
cout << a1.m_c << endl;

a1.m_c = 20;
cout << a2.m_c << endl;

a2.m_c = 90;
cout << a3.m_c << endl;

// 静态成员也可以通过类型进行访问,需要用到 :: 操作符
Test::m_c = 200;
cout << a3.m_c << endl;

return 0;

}

面向对象的模型:
1、C++类对象中的成员变量和成员函数是分开存储的。C语言中的内存四区模型仍然有效
2、C++中类的普通成员函数都隐式包含一个指向当前对象的this指针。
3、静态成员函数、成员变量属于类
静态成员函数与普通成员函数的区别:
静态成员函数不包含指向具体对象的指针
普通成员函数包含一个指向具体对象的指针

this指针:
#include 
using namespace std;
class Test
{
public:
    Test(int a, int b) //—> Test(Test *this, int a, int b)
    {
        this->a = a;
        this-> b = b;
    }
    void printT()
    {
        cout<<"a: " <<a <<endl;
        cout<< "b: " << this->b <<endl;
    }
protected:
private:
    int a;
    int b;
};
 
void main()
{
 
    Test t1(1, 2);
    t1.printT();// ===> printT(&t1)
    cout<<“hello…”<<endl;
    system(“pause”);
    return ;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值