C++类和对象的学习【part2:对象特性】
构造函数和析构函数
完成对对象的初始化和清理。
编译器强制,自动调用。
构造函数语法:
类名(){}
析构函数语法:
~类名(){}
构造函数的分类及调用
分类方式:
- 按参数分类:有参构造和无参构造
- 按类型分类:普通构造和拷贝构造
三种调用方式:
- 括号法
- 显示法
- 隐式转换法
具体程序如下:
// arrayone.cpp -- small arrays of integers
#include <iostream>
using namespace std;
//构造函数的分类和调用
class Person
{
public: //一定要写在public权限之下
Person()
{
cout << "无参构造" << endl;
}
Person(int a)
{
age = a;
cout << "有参构造" << endl;
}
Person(const Person &p) //记住这种写法先,完成拷贝一份一样的进行构造
{
cout << "拷贝构造" << endl;
//将传入Person身上的属性,拷贝到当前类上
age = p.age;
}
~Person()
{
cout << "析构" << endl;
}
int age;
};
int main()
{
//括号法
Person p1; //默认构造函数(无参构造)
Person p2(10); //有参构造
Person p3(p2); //拷贝构造
//注意事项:调用默认构造函数时,不要加(),否则就会认为是函数声明
cout << "p2's age = " << p2.age << endl;
cout << "p3's age = " << p3.age << endl;
//显示法
Person p4;
Person p5 = Person(99);
Person p6 = Person(p5);
//单独一个这个,是匿名对象,当前行结束,系统立即回收匿名对象
Person(50);
//注意事项:不要利用拷贝构造,初始化匿名对象,编译器认为是Person(p3) === Person p3;
//隐式法
Person p7 = 10; //相当于Person p7 = person(10);(有参构造)
Person p8 = p7; //拷贝构造
system("pause");
return 0;
}
这里展示了不同种类,不同调用方式下的构造函数使用。
拷贝构造函数的调用时机
用法:
- 使用一个已经构建的对象初始化一个新对象
- 值传递给函数参数传值
- 以值方式返回局部对象
// arrayone.cpp -- small arrays of integers
#include <iostream>
using namespace std;
//构造函数的分类和调用
class Person
{
public:
Person()
{
cout << "Person的默认构造函数调用" << endl;
}
Person(int age)
{
age_ = age;
cout << "Person的有参构造函数调用" << endl;
}
Person(const Person &p)
{
age_ = p.age_;
cout << "Person的拷贝构造函数调用" << endl;
}
~Person()
{
cout << "Person的析构函数调用" << endl;
}
int age_;
};
//使用一个已经构建的对象初始化一个新对象
void test01()
{
Person p1(20);
Person p2(p2);
}
//值传递给函数参数传值
void doit(Person p)
{
}
void test02()
{
Person p;
doit(p);
}
//以值方式返回局部对象
Person donow()
{
Person p1;
return p1;
}
void test03()
{
Person p = donow();
}
int main()
{
//test01();
//test02();
test03();
system("pause");
return 0;
}
这里展示了不同方法下,拷贝构造函数的调用时机(调用方法)。
注意:拷贝构造函数的定义方法是比较特殊的,如下:
Person(const Person &p)
{
age_ = p.age_;
cout << "Person的拷贝构造函数调用" << endl;
}
所谓拷贝构造,就是复制了一个新的类,尤其是以值方式返回局部对象,涉及到的就是返回了一个新的对象,这个对象不是p1的本体,若想为p1的本体,应当返回的是引用,即:
return *this;
并且,函数返回类型为引用,即:
Person& (const Person &p)
{
age_ = p.age_;
cout << "Person的拷贝构造函数调用" << endl;
}
构造函数调用规则
创建一个类,C++编译器会给每个类都添加至少3个函数。
注意:如果写了有参构造函数,就不再自动默认构造,但依然提供拷贝构造。
这里的拷贝构造可以理解为自动添加了赋值语句,将类A信息拷贝至类B。
注意:如果写了拷贝构造函数,编译器就不再提供其他的普通构造函数了。
这两个注意的意思是要自己写编译器不提供的构造函数(如果要用的话)。
深拷贝和浅拷贝
浅拷贝:简单的赋值
深拷贝:在堆区重新申请内存空间,进行
浅拷贝问题:堆区内存重复释放
初始化列表来初始化属性
这里介绍初始化列表来初始化属性的值,程序如下:
// arrayone.cpp -- small arrays of integers
#include <iostream>
using namespace std;
//构造函数的分类和调用
class Person
{
public:
//传统初始化操作
// Person(int a, int b, int c)
// {
// A_ = a;
// B_ = b;
// C_ = c;
// }
//通过初始化列表初始化属性
Person() : A_(10), B_(20), C_(30)//不必注释该行,因为可以利用构造函数重载实现
{
}
//或者
Person(int a, int b, int c) : A_(a), B_(b), C_(c)
{
}
int A_;
int B_;
int C_;
};
void test01()
{
//Person p(10, 20, 30);
// Person p;
Person p(30, 20, 10);
cout << "A_ = " << p.A_ << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
这里介绍了三种初始化方法。
其中,传统初始化就是利用有参构造函数,通过传入数值来进行初始化。
进而第二种是列表初始化,但是这种列表只能初始化为固定的值,因为不再赘述。
第三种初始化实质是第一种的升级改造,简化了写法,一目了然,很方便。
这里用到了函数重载,本例中保留了两个构造函数,在调用的时候可以触发函数重载,从而选择合适的构造函数。
(笔者本来以为写错了,准备注释掉上一个构造函数,但发现运行无误,之后baidu发现是出现了函数重载,不得不肃然起敬!)
类对象作为类成员
我们在定义类的时候,可以把其他类作为类成员定义,在以下代码就展示了这一功能,并且加入了初始化列表。
// arrayone.cpp -- small arrays of integers
#include <iostream>
using namespace std;
#include <string>
//类对象作为类成员
class Phone
{
public:
Phone(string PName) : PName_(PName)
{
//PName_ = PName;
cout << "Phone构造函数" << endl;
}
string PName_;
};
class Person
{
public:
//相当于: Phone phone_ = PName;
Person(string name, string PName) : name_(name), phone_(PName)
{
cout << "Person构造函数" << endl;
}
string name_;
Phone phone_;
};
//当其他类对象作为本类成员,先构造其他类对象,再构造自身
//析构的顺序正好相反
void test01()
{
Person p("张三", "苹果手机");
cout << p.name_ << "拿着" << p.phone_.PName_ << endl;
}
int main()
{
test01();
system("pause");
return 0;
}
另外需要注意的是,在应用这一方法时,会先构造其他类对象,再构造自身,而析构顺序正好相反。
这里可以理解为现有零件,才能组装成完整的类,所以是先构造用到的类对象。
程序运行结果如下:
静态成员
静态成员就是在成员变量和成员函数前加上关键字static,称为静态成员。
静态成员分为:
- 静态成员变量
- 所有对象共享同一份数据
- 在编译阶段分配内存
- 类内声明,类外初始化
- 静态成员函数
- 所有对象共享同一个函数
- 静态成员函数只能访问静态成员变量
关于静态变量,找到了一篇不错的文章:
https://blog.csdn.net/ichliebecamb/article/details/85097922?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-1.compare