提示:上节课内容,构造函数是一种特殊的成员函数,在创建对象的时候自动调用,对对象的数据成员进行初始化。
一、转换构造函数
1.构造函数的作用 初始化和类型转化(转化构造函数)
转化构造函数:带一个参数的构造函数,能够将其他类型转换为类类型。
2.类的构造函数只有一个参数是非常危险的,因为编译器可以使用这种构造函数把参数的类型隐式转换为类类型。
二、赋值与初始化的区别
Test& operator=(const Test& other);
Test& Test:: operator =(const Test& other)
{
num_ = other.num_;
cout<<"Test:: operator" << endl;
return *this;
}
int main(void)
{
Test t = 10;
t = 20;
return 0;
}
注:explicit关键字,表示只提供给类的构造函数使用的关键字,编译器不会把声明为explicit的构造函数用于隐式转换,能够在程序代码中显示创建对象。
explicit Test(int num);
现在代码就不能进行隐式转换了
三、(构造函数与析构函数第三节内容)
1.构造函数初始化列表
什么是构造函数初始化列表呢? 举例如下:
2.对象成员及其初始化
对数据成员的初始化推荐放在初始化列表当中,包括普通数据成员和对象数据成员。
如果对象所对应的类没有构造函数,初始化一定要放在初始化列表当中。如果有默认构造函数,可以省略
代码如下(示例):
#include<iostream>
using namespace std;
class Object
{
public:
Object(int num) : num_(num)
{
cout << "Object…"<<num_ << endl;
}
~Object()
{
cout << "~Object…" <<num_<< endl;
}
private:
int num_;
};
class Container
{
public:
Container(int obj1=0,int obj2=0) : obj1_(obj1),obj2_(obj2)
{
cout << "Container" << endl;
}
~Container()
{
cout << "~Container" << endl;
}
private:
Object obj1_;
Object obj2_;
};
int main(void)
{
Container c(10,20);
return 0;
}
3.const 成员、引用成员初始化
const成员的初始化,只能在构造函数初始化列表中进行;
引用成员的初始化也只能在构造函数初始化列表中进行;
对象成员(对象所对应的类没有默认构造函数)的初始化,也只能在构造函数初始化列表中进行。
#include<iostream>
using namespace std;
class Object
{
public:
Object(int num=0) : num_(num),knum_(100)
{
cout << "Object…" << num_ << endl;
}
~Object()
{
cout << "~Object…" << num_ << endl;
}
private:
int num_;
const int knum_;
int& refnum_;
};
int main(void)
{
Object obj(10);
return 0;
}
#include<iostream>
using namespace std;
class Object
{
public:
enum E_TYPE
{
TYPE_A = 100, TYPE_B = 200
};
public:
Object(int num = 0) : num_(num), knum_(100),refnum_(num_)
{
cout << "Object…" << num_ << endl;
}
~Object()
{
cout << "~Object…" << num_ << endl;
}
void DisplayKnum()
{
cout << "knum=" << knum_ << endl;
}
private:
int num_;
const int knum_;
int& refnum_;
};
int main(void)
{
Object obj1(10);
Object obj2(20);
obj1.DisplayKnum();
obj2.DisplayKnum();
cout << obj1.TYPE_A << endl;
cout << obj2.TYPE_A << endl;
cout << Object::TYPE_A << endl;
return 0;
}
四、(构造函数与析构函数第四节内容)
1.拷贝构造函数
功能:使用一个已经存在的对象来初始化一个新的同一类型的对象
声明:只有一个参数并且参数为该类对象的引用
如果类中没有说明拷贝构造函数,则系统自动生成一个缺省复制构造函数,作为该类的公有成员
Test(const Test& other);
Test::Test(const Test& other)
{
num_ = other.num_;
cout<<"Inicializing with other"<<num_ << endl;
}
int main(void)
{
Test t(10);
Test t2(t);
return 0;
}
说明:为什么拷贝构造函数参数必须是对象的引用?非法的。引用不创建地址空间,与实参共享同一块地址空间。不会再构造一个对象,使用引用减少内存复制
2. 拷贝构造函数调用的几种情况
1. 当函数的形参是类的对象,调用函数时,进行形参与实参结合时使用。这时要在内存新建立一个局部对象,并把实参拷贝到新的对象中。理所当然也调用拷贝构造函数。
2. 当函数的返回值是类对象,函数执行完成返回调用者时使用。理由也是要建立一个临时对象中,再返回调用者。为什么不直接要用返回的局部对象呢?因为局部对象在离开建立它的函数时就消亡了,不可能在返回点用函数后继续生存,所以在处理这种情况时,编译系统会在调用函数的表达式中创建一个无名临时对象,该临时对象的生存周期只在函数调用处的表达式中。
五、对象的使用
1.static成员独立于对象而存在,也就是说它不属于某个对象的成员,能被全体对象所共享
2.统计类类型对象创建的个数 用static成员来实现
3.非static成员它属于类对象,每个对象都有一份拷贝
4.static成员函数没有this指针,不能访问非static成员,也不能调用非static成员函数
提示:静态成员的展示
#include<iostream>
using namespace std;
class Date
{
public:
Date(int year) :year_(year)
{
}
static bool IsLeapYear(int year)
{
return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}
bool IsLeapYear()
{
return (year_ % 4 == 0 && year_ % 100 != 0) || (year_ % 400 == 0);
}
private :
int year_;
};
int main(void)
{
Date d(2012);
cout << d.IsLeapYear() << endl;
cout <<Date:: IsLeapYear(2010) << endl;
return 0;
}
1.四种对象的作用域与生存期
1.栈对象(隐含调用构造函数,程序中没有显示调用)
2.堆对象(隐含调用构造函数,程序中没有显示调用,需要显示释放)
3.全局对象、静态全局对象
全局对象的构造先于main函数
**已初始化的全局变量或静态全局对象存储于.data段中
未初始化的全局变量或静态全局对象存储与.bss段中**
4.静态局部对象
?作用域不等同于生存期
提示:栈对象、堆对象代码展示
#include<iostream>
using namespace std;
class Test
{
public:
Test(int n):n_(n)
{
cout << "Test"<<n_<<"…" << endl;
}
~Test()
{
cout << "~Test" << n_ << "…" << endl;
}
private:
int n_;
};
Test g(100);
static Test g2(200);
int main(void)
{
cout << "Entering main…" << endl;
Test t(10);
{
Test t(20);
}
{
Test* t3 = new Test(30);
delete t3;
}
{
static int n3;
static int n4 = 100;
static Test t4(333);
}
cout << "Exiting main…" << endl;
}
提示:.bss未初始化的数据段在可执行文件中不占用空间
2.static用法总结
1.用于函数内部修饰变量,静态变量,这种变量的生存期长于该函数,使得函数具有一定的状态。使静态变量一般是不可重入的,也不是线程安全的
2.用在文件级别,修饰变量或函数,表示该变量或函数只在本文件可见
3.C++中
用于修饰类的数据成员,所谓“静态成员”。这种数据成员的生存期大于class的对象
用于修饰class的成员函数,即“静态成员函数”。这种成员函数只能访问静态成员和其他静态成员函数,不能访问非静态成员和非静态成员函数。
3.static与单例模式
单例模式是一种设计模式(软件工程的用例),禁止拷贝
#include<iostream>
using namespace std;
class Singleton
{
public:
static Singleton* GetInstance()
{
if (instacne_ == NULL)
{
instacne_ = new Singleton;
}
return instacne_;
}
~Singleton()
{
cout << "~Singleton…" << endl;
}
class Garbo
{
public:
~Garbo()
{
if (Singleton::instacne_ !=NULL)
{
delete instacne_;
}
}
};
private:
Singleton()
{
cout << "Singleton…" << endl;
}
static Singleton* instacne_;
static Garbo garbo_;
};
Singleton::Garbo Singleton::garbo_;
Singleton* Singleton::instacne_;
int main(void)
{
Singleton*s1= Singleton::GetInstance();
Singleton*s2 = Singleton::GetInstance();
return 0;
}
六、const成员函数
- const成员函数不会修改对象的状态
- 定义一个常量时必须初始化
- const成员函数只能访问数据成员的值,而不能修改它
- 用mutable修饰的数据成员即使在const对象或在const成员函数中都可以被修改
- 在类中,如果有const成员,const成员的初始化只能在构造函数初始化列中进行
提示:下节运行实例理解数据抽象与封装(进度拉满能不能,我这太想学完刷leetcode了)
|