前言
接上一篇内容。本节是讲解类作用域,包括块作用域、文件作用域、函数原型作用域、函数作用域、类作用域
一、类作用域
1.作用域
代码如下(示例):
#include <iostream>
using namespace std;
class Test
{
public:
int num_;//作用域在类范围内,称为类作用域
};
//num_=20 Error 类外部不可以赋值
int num_ = 20;//True,作用域是文件作用域,与类中的num_不同作用域
int add(int a, int b);//a,b两个标识符的作用域为函数原型作用域
int main(void)
{
int num_;//块作用域
{
int num_ = 100;//也是块作用域,不影响外部作用域
}
cout << num_ << endl;
cout << ::num_ << endl;//文件作用域中的num_变量
return 0;
}
int add(int a, int b)//形参也属于块作用域
{
return a + b;
}
int test()
{
LABEL1://三个标签是函数作用域,在函数内部是有效的
cout << "label1" << endl;
goto LABEL3;
LABEL2:
cout << "label2" << endl;
LABEL3:
cout << "label3" << endl;
}
2.前向声明
C++中必须先定义,才能够实例化。
两个类需要相互引用形成一个环形引用时,无法先定义使用。这时候需要使用到前向声明
⭐前向声明的类不能实例化。
//相互包含时不成立的,出现错误,需要用到前向声明
class A {
public:
A(void);
B b_;//包含B头文件
};
class B {
public:
B(void);
A a_;//包含A头文件
};
3.嵌套类
1.从作用域的角度看,嵌套类被隐藏在外围类之中,该类名只能在外围类中使用。如果在外围类的作用域使用该类名,需要加名字限定。
2.外围类不能访问嵌套类的私有成员,同样嵌套类也不能访问外围类的私有成员。
⭐举例
void Outer::Iner::Fun()
{
cout << "Inner::Fun…" << endl;
}
#include <iostream>
using namespace std;
class Outer
{
class Iner {
public:
void Fun() {
cout << "Iner::Fun…" << endl;
}
};
public://嵌套类为外围提供服务
Iner obj_;
void Fun()
{
cout << "Outer::Fun…" << endl;
obj_.Fun();
}
};
int main(void)
{
Outer o;
o.Fun();
return 0;
}
4.局部类
局部类中不能有静态成员。
void Fun()
{
class LocalClass//局部类只能在函数内有效
{
public:
int num_;
void Init(int num)
{
num_ = num;
}
void Display()
{
cout << "num=" << num_ << endl;
}
};
LocalClass lc;
lc.Init(10);
lc.Display();
}
二、构造函数和析构函数
1.构造函数
构造函数是特殊的成员函数。创建类类型的新对象,系统自动会调用构造函数,构造函数是为了保证对象的每个数据成员都被正确初始化。
1.函数名与类名完全相同
2.不能定义构造函数的类型,也不能使用void
3.通常情况下构造函数应声明公有函数,否则它不能像其他成员函数那样被显式调用
4.⭐构造函数允许被重载,构造函数可以有任意类型和任意个数的参数,一个类可以有多个构造函数(重载)。
5.不带参数的构造函数,系统会自动产生一个默认的构造函数
//头文件Test.h
#ifndef _TEST_H_
#define _TEST_H_
class Test
{
public:
Test();
private:
int num_;
};
#endif // ! _TEST_H_
//构造函数Test.cpp
#include"Test.h"
#include <iostream>
using namespace std;
Test::Test()
{
num_ = 0;
cout << "Initializing Default" << endl;
}
class Test
{
public:
Test();//重载
Test(int num);
//如果类不提供任何一个构造函数,系统将为我们提供一个不带参数的默认的 构造函数
void Display();
private:
int num_;
};
2.构造函数和new运算符
int main(void)
{//构造函数自动被调用
Test t;
t.Display();
Test t2(10);//类定义了一个对象,新建一个对象时函数被调用输出
t2.Display();
Test* t3 = new Test(20);//new operator不仅仅分配了内存,还调用了构造函数
t3->Display();
delete t3;//不仅释放内存,还调用了析构函数
return 0;
}
3.全局对象的构造先于main函数
代码如下(示例):
#include"Test.h"
#include<iostream>
using namespace std;
Test t(10);
int main(void)
{
cout << "Entering main…" << endl;
cout << "Exiting main… " << endl;
return 0;
}
4.析构函数
1.函数名与类名相似(前面多了一个字符“~”)
2.没有返回类型 没有参数 析构函数不能被重载
3.没有定义析构函数,编译器会自动生成一个默认析构函数,其格式如下:
类名::~默认析构函数名(){}
析构函数与数组的关系
Test* t2 = new Test(2);
delete t2;
#include"Test.h"
#include<iostream>
using namespace std;
int main(void) {
Test t[2] = { 10,20 };//两个对象,调用两次构造函数
return 0;
}
delete不仅仅释放内存还调用了析构函数
int main(void) {
Test t[2] = { 10,20 };//两个对象,调用两次构造函数
Test* t2 = new Test(2);
delete t2;
Test* t3 = new Test[2];
delete[] t3;
return 0;
}
总结
构造函数是一种特殊的成员函数
在创建对象的时候自动调用,对对象的数据成员进行初始化
栈区中创建的对象,在生存期结束时会自动调用析构函数
在堆上创建的对象,要有程序员显式的调用delete释放该对象,同时调用析构函数
全局对象的构造先于main函数