标签:containe 方式 shell 网络 必须 深浅拷贝 amp 通过 jpg
问题:对象中成员变量的初始值是多少?
Demo
#include <stdio.h>
class Test
{
private:
int i;
int j;
public:
int getI() { return i; }
int getJ() { return j; }
};
Test gt; //全局对象:静态存储区
int main()
{
printf("gt.i = %d\n", gt.getI()); //0
printf("gt.j = %d\n", gt.getJ()); //0
Test t1; //栈
printf("t1.i = %d\n", t1.getI()); //134513995
printf("t1.j = %d\n", t1.getJ()); //5984244
Test* pt = new Test; //堆
printf("pt->i = %d\n", pt->getI()); //
printf("pt->j = %d\n", pt->getJ()); //
delete pt;
return 0;
}
从程序设计的角度,对象只是变量,因此
问题:程序中如何对一个对象进行初始化,使得不管在什么地方创建类对象,其成员变量的初始值都为固定值?
解决方案1
在类中提供一个 public
的 initialize
函数
对象创建后立即调用 initialize
函数进行初始化
示例:初始化函数
Demo
#include <stdio.h>
class Test
{
private:
int i;
int j;
public:
int getI() { return i; }
int getJ() { return j; }
//初始化函数
void initialize()
{
i = 1;
j = 2;
}
};
Test gt;
int main()
{
//显式调用初始化函数
gt.initialize();
printf("gt.i = %d\n", gt.getI()); //1
printf("gt.j = %d\n", gt.getJ()); //2
Test t1;
//没有显式调用初始化函数,运行结果未知
//t1.initialize();
printf("t1.i = %d\n", t1.getI()); //7469952
printf("t1.j = %d\n", t1.getJ()); //134514267
//没有立即调用,运行结果未知
t1.initialize();
Test* pt = new Test;
//显式调用初始化函数
pt->initialize();
printf("pt->i = %d\n", pt->getI()); //1
printf("pt->j = %d\n", pt->getJ()); //2
delete pt;
return 0;
}
存在的问题
initialize
只是一个普通函数,必须显式调用initialize
函数,运行结果是不确定的initialize
函数 ,运行结果是不确定的解决方案2:构造函数
C++ 中可以定义与类名相同的特殊的成员函数,这种特殊的成员函数叫做构造函数
示例:构造函数
Demo
#include <stdio.h>
class Test
{
private:
int i;
int j;
public:
int getI() { return i; }
int getJ() { return j; }
//构造函数
Test()
{
printf("Test() Begin\n");
i = 1;
j = 2;
printf("Test() End\n");
}
};
Test gt;
int main()
{
printf("gt.i = %d\n", gt.getI());
printf("gt.j = %d\n", gt.getJ());
Test t1;
printf("t1.i = %d\n", t1.getI());
printf("t1.j = %d\n", t1.getJ());
Test* pt = new Test;
printf("pt->i = %d\n", pt->getI());
printf("pt->j = %d\n", pt->getJ());
delete pt;
return 0;
}
编译运行
Test() Begin
Test() End
gt.i = 1
gt.j = 2
Test() Begin
Test() End
t1.i = 1
t1.j = 2
Test() Begin
Test() End
pt->i = 1
pt->j = 2
带有参数的构造函数
构造函数可以根据需要定义参数
一个类中可以存在多个重载的构造函数
构造函数的重载遵循 C++ 重载的规则
class Test
{
public:
Test(int c)
{
//use v to initialize member
}
};
注意:对象定义和对象声明不同
对象定义:申请对象的空间并调用构造函数
对象声明:告诉编译器存在这样一个对象
Test t; //定义对象并调用构造函数
int main()
{
extern Test t; //告诉编译器存在名为t的Test对象,通过链接器在各个目标文件中寻找t的定义
return 0;
}
构造函数的自动调用
class Test
{
public:
Test(){}
Test(int v){}
};
int main()
{
Test t; //调用Test()
Test t1(1); //调用Test(int v)
Test t2 = 1; //调用Test(int v)
}
示例:带参数的构造函数
Demo
#include <stdio.h>
class Test
{
public:
Test()
{
printf("Test()\n");
}
Test(int v)
{
printf("Test(int v), v = %d\n", v);
}
};
int main()
{
Test t; // 调用 Test()
Test t1(1); // 调用 Test(int v)
Test t2 = 2; // 调用 Test(int v)
int i(100); //初始化(如果是类类型,会调用构造函数)
int j;
j = 2; //赋值操作
printf("i = %d\n", i);
return 0;
}
编译运行
Test()
Test(int v), v = 1
Test(int v), v = 2
i = 100
构造函数的调用
示例:构造函数的手动调用 => 创建一个对象数组
Demo
#include <stdio.h>
class Test
{
private:
int m_value;
public:
Test() {
printf("Test()\n");
m_value = 0;
}
Test(int v) {
printf("Test(int v),v = %d\n", v);
m_value = v;
}
int getValue() {
return m_value;
}
};
int main()
{
Test ta[3];
for (int i = 0; i < 3; ++i) {
printf("ta[%d].getValue() = %d\n", i, ta[i].getValue());
}
return 0;
}
编译运行:可以看到对象数组 ta
中的每一个类对象的成员变量 m_value
值都相同:0
Test()
Test()
Test()
ta[0].getValue() = 0
ta[1].getValue() = 0
ta[2].getValue() = 0
修改:创建对象值不同的对象数组
#include <stdio.h>
class Test
{
private:
int m_value;
public:
Test() {
printf("Test()\n");
m_value = 0;
}
Test(int v) {
printf("Test(int v), v = %d\n", v);
m_value = v;
}
int getValue() {
return m_value;
}
};
int main()
{
Test ta[3] = {Test(), Test(1), Test(2)}; //手动调用构造函数
for(int i=0; i<3; i++) {
printf("ta[%d].getValue() = %d\n", i , ta[i].getValue());
}
Test t = Test(100); //手动调用构造函数 => 完成定义对象
printf("t.getValue() = %d\n", t.getValue());
return 0;
}
编译运行
Test()
Test(int v), v = 1
Test(int v), v = 2
ta[0].getValue() = 0
ta[1].getValue() = 1
ta[2].getValue() = 2
Test(int v), v = 100
t.getValue() = 100
需求:开发一个数组类解决原生数组的安全性问题
提供函数获取数组长度
提供函数获取数组元素
提供函数设置数组元素
Demo:IntArray
类
//IntArray.h
#ifndef _INTARRAY_H_
#define _INTARRAY_H_
class IntArray
{
private:
int m_length; //长度
int* m_pointer; //数据
public:
IntArray(int len); //构造函数
int length(); //获取长度
bool get(int index, int& value); //获取数组指定位置的元素
bool set(int index ,int value); //设置数组指定位置的元素
void free(); //释放所申请的堆空间
};
#endif
//IntArray.cpp
#include "IntArray.h"
IntArray::IntArray(int len)
{
m_pointer = new int[len];
for(int i=0; i<len; i++)
{
m_pointer[i] = 0;
}
m_length = len;
}
int IntArray::length()
{
return m_length;
}
bool IntArray::get(int index, int& value)
{
bool ret = (0 <= index) && (index < length());
if( ret )
{
value = m_pointer[index];
}
return ret;
}
bool IntArray::set(int index, int value)
{
bool ret = (0 <= index) && (index < length());
if( ret )
{
m_pointer[index] = value;
}
return ret;
}
void IntArray::free()
{
delete[] m_pointer;
}
//main.cpp
#include <stdio.h>
#include "IntArray.h"
int main()
{
IntArray a(5);
for(int i=0; i<a.length(); i++)
{
a.set(i, i + 1);
}
for(int i=0; i<a.length(); i++)
{
int value = 0;
if( a.get(i, value) )
{
printf("a[%d] = %d\n", i, value);
}
}
a.free();
return 0;
}
编译运行
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 4
a[4] = 5
两个特殊的构造函数
const class_name&
的构造函数示例:特殊的构造函数
Demo
#include <stdio.h>
class Test
{
private:
int i;
int j;
public:
int getI()
{
return i;
}
int getJ()
{
return j;
}
/*Test(const Test& t)
{
i = t.i;
j = t.j;
}
Test()
{
}*/
};
int main()
{
Test t1;
Test t2 = t1;
printf("t1.i = %d, t1.j = %d\n", t1.getI(), t1.getJ());
printf("t2.i = %d, t2.j = %d\n", t2.getI(), t2.getJ());
return 0;
}
拷贝构造函数的意义
int i = 1; int j = i;
深浅拷贝
示例:对象的初始化
Demo
#include <stdio.h>
class Test
{
private:
int i;
int j;
int* p;
public:
int getI()
{
return i;
}
int getJ()
{
return j;
}
int* getP()
{
return p;
}
/*
Test(const Test& t)
{
i = t.i;
j = t.j;
p = new int;
*p = *t.p;
}
*/
Test(int v)
{
i = 1;
j = 2;
p = new int;
*p = v;
}
void free()
{
delete p;
}
};
int main()
{
Test t1(3);
Test t2(t1);
printf("t1.i = %d, t1.j = %d, *t1.p = %d\n", t1.getI(), t1.getJ(), *t1.getP());
printf("t2.i = %d, t2.j = %d, *t2.p = %d\n", t2.getI(), t2.getJ(), *t2.getP());
t1.free();
t2.free(); //内存泄漏:0x8e6a008被释放了两次
return 0;
}
编译运行
t1.i = 1, t1.j = 2, t1.p = 0x8e6a008
t2.i = 1, t2.j = 2, t2.p = 0x8e6a008
问题:什么时候需要进行深拷贝?
对象中有成员指代了系统中的资源
分析:t1
和 t2
的 m_pointer
指向同一块内存,之后会被释放两次
一般性原则:自定义拷贝构造函数,必然需要实现深拷贝
IntArray
类的改进
Demo
//IntArray.h
#ifndef _INTARRAY_H_
#define _INTARRAY_H_
class IntArray
{
private:
int m_length;
int* m_pointer;
public:
IntArray(int len);
IntArray(const IntArray& obj); //拷贝构造函数
int length();
bool get(int index, int& value);
bool set(int index ,int value);
void free();
};
#endif
//IntArray.cpp
#include "IntArray.h"
IntArray::IntArray(int len)
{
m_pointer = new int[len];
for(int i=0; i<len; i++)
{
m_pointer[i] = 0;
}
m_length = len;
}
IntArray::IntArray(const IntArray& obj)
{
m_length = obj.m_length;
m_pointer = new int[obj.m_length];
for(int i=0; i<obj.m_length; i++)
{
m_pointer[i] = obj.m_pointer[i];
}
}
int IntArray::length()
{
return m_length;
}
bool IntArray::get(int index, int& value)
{
bool ret = (0 <= index) && (index < length());
if( ret )
{
value = m_pointer[index];
}
return ret;
}
bool IntArray::set(int index, int value)
{
bool ret = (0 <= index) && (index < length());
if( ret )
{
m_pointer[index] = value;
}
return ret;
}
void IntArray::free()
{
delete[] m_pointer;
}
//main.cpp
#include <stdio.h>
#include "IntArray.h"
int main()
{
IntArray a(5);
for(int i=0; i<a.length(); i++)
{
a.set(i, i + 1);
}
for(int i=0; i<a.length(); i++)
{
int value = 0;
if( a.get(i, value) )
{
printf("a[%d] = %d\n", i, value);
}
}
IntArray b = a;
for(int i=0; i<b.length(); i++)
{
int value = 0;
if( b.get(i, value) )
{
printf("b[%d] = %d\n", i, value);
}
}
a.free();
b.free();
return 0;
}
编译运行
1
2
3
4
5
1
2
3
4
5
标签:containe 方式 shell 网络 必须 深浅拷贝 amp 通过 jpg
原文地址:https://www.cnblogs.com/bky-hbq/p/13715195.html