const在类中的扩展
C++引入的面向对象的概念之后,C 语言中的一些比如 static/const 等原有语意,作一些升级处理,此时既要保持兼容,还要保持不冲突。
const 修饰数据成员
const 修饰数据成员,称为常数据成员,可能被普通成员函数和常成员函数来使用, 不可以更改。 C++中const必须初始化 可以在类中(不推荐),或初始化参数列表中(这是在类对象生成之前唯一的一次改变 const 成员值的机会了)
const 修饰数据成员不初始化存在的问题
我们先给出一个类内私有数据的const类型:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
}
~MyClass()
{
}
private:
const int x;
};
int main()
{
MyClass a;
return 0;
}
这个时候编译会出现问题:
注意:
const 修饰类数据成员必须要初始化,我们在类内数据没有初始化,在构造器内也没又进行初始化,即使我们自己不在构造器里面进行初始化,那么系统默认自带的构造器也是一个无参空体构造器,也不会初始化。
那么并不是我们在构造器里面进行初始化之后,编译就能通过。
例如:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
x = 100;
}
~MyClass()
{
}
private:
const int x;
};
int main()
{
MyClass a;
return 0;
}
这个时候也不能编译通过:
编译器会提示:
解决上述问题的const数据成员初始化方式
定义的时候初始化
我们把上面的x进行初始化编译就可以通过:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass()
{
x = 100;
}
~MyClass()
{
}
private:
const int x = 100;
};
int main()
{
MyClass a;
return 0;
}
但是我们在平时的使用过程,在类对象中我们不建议这样的使用方法,我们希望一个对象的数据成员在初始的时候没有值,然后通过构造器进行构造,或者其他方式传递我们所需要的值。上面的const int生成的100放在了我们之后使用的每一个类对象里面,这是很不合适的。
通过对象传递参数使用参数列表进行初始化
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass(int i):x(i)
{}
~MyClass()
{}
void dis()
{
cout << x << endl;
}
private:
const int x;
int y;
};
int main()
{
MyClass a(666);
a.dis();
return 0;
}
运行结果为:
这也是唯一的一次可以初始化的机会,
也就是说const修饰的数据成员可以在非const函数中使用,但是不可以更改。
通过初始化形参列表进行初始化
除了我们在类内定义类内数据的时候直接初始化,我们还可以在初始化列表进行初始化。
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass():x(100)
{
cout << "const x" << x << endl;
}
~MyClass()
{
}
private:
const int x;
};
int main()
{
MyClass a;
return 0;
}
运行结果为:
初始化参数列表,提高了效率。
初始化参数列表如何提高效率
我们通过举例进行说明:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass() :x(100), y(200)
{
cout << "const x" << x << endl;
}
~MyClass()
{
}
private:
const int x;
int y;
};
int main()
{
MyClass a;
return 0;
}
我们上面的y初始化是在类对象创建的时候被初始化。
我们换一种方式进行初始化:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass() :x(100)
{
this->y = 200;
cout << "const x" << x << endl;
}
~MyClass()
{
}
private:
const int x;
int y;
};
int main()
{
MyClass a;
return 0;
}
上面我们使用this指针进行初始化,this指针发生在对象创建完成之后。
我们再给出修改:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass() :x(100),this->y(200)
{
this->y = 200;
cout << "const x" << x << endl;
}
~MyClass()
{
}
private:
const int x;
int y;
};
int main()
{
MyClass a;
return 0;
}
上面代码编译器会报错:
无this标识符,那么说明类对象在创建的时候是没有生成this指针的。
所以使用初始化参数列表进行初始化效率更高。
初始化参数列表拓展
除了提高效率,也可以为一些新扩展的功能提供一个解决场所或者办法
举例进行:我们在使用的过程中也会对类内数据使用引用
我们在数据成员引用z
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass():x(100),y(200)
{
cout << "const x" << x << endl;
}
~MyClass()
{
}
private:
const int x;
int y;
int& z;
};
int main()
{
MyClass a;
return 0;
}
编译不能通过:
编译器会提示
这里的未提供初始值设定项就是引用。
那么我们就需要引用到类内:
#include <iostream>
using namespace std;
class MyClass
{
public:
MyClass(int & zz):x(100),y(200),z(zz)
{
cout << "const x" << x << endl;
cout <<z<< endl;
}
~MyClass()
{
}
private:
const int x;
int y;
int& z;
};
int main()
{
int z = 300;
MyClass a(z);
return 0;
}
我们就通过形参列表使用引用让类内使用类外数据。
运行结果为:
那么向上面
const int x;
int &z ;
的问题在我们之前学习struct里面是没有的。
const 修饰函数成员
const 修饰函数的位置
const 修饰函数放在,声明之后,实现体之前,大概也没有别的地方可以放了。
void dis() const
const 可以修饰全局函数吗?
const 修饰类成员函数,不可以修饰全局函数
读者可以自行验证
const 成员函数的意义
承诺在本函数内部不会修改类内的数据成员,为此,也只能调用承诺不会改变成员的其它 const 成员函数,而不能调用其它非 const 成员函数。
类内const函数不允许修改类内的数据成员
我们接下来对于上面的意义进行解释说明:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void dis() const
{
_x = 200;
cout << _x << endl;
cout << _y << endl;
}
private:
int _x;
const int _y;
};
int main()
{
A a(3,4);
a.dis();
return 0;
}
上面代码在运行的时候就会出现问题:
不允许在类内const对于类内数据成员的值进行修改。也就是承诺在本函数内部不会修改类内的数据成员。
类内const函数不允许调用能够修改类内数据成员的函数
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void dis() const
{
fun();
cout << _x << endl;
cout << _y << endl;
}
void fun()
{
_x = 200;
}
private:
int _x;
const int _y;
};
int main()
{
A a(3,4);
a.dis();
return 0;
}
上面代码编译器也会报错:
也就是说,不允许调用能够修改类内数据成员的函数。及就是只能调用承诺不会改变成员的其它 const 成员函数,而不能调用其它非 const 成员函数。
如果调用的都是const成员函数,就不会出现问题:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void dis() const
{
cout << _x << endl;
cout << _y << endl;
fun();
}
void fun() const
{
cout << _x << endl;
cout << _y << endl;
}
private:
int _x;
const int _y;
};
int main()
{
A a(3,4);
a.dis();
return 0;
}
运行结果为:
const 构成重载
接触过的const重载
我们在之前已经接触过const重载,例如:
#include <iostream>
using namespace std;
int add(int & a, int & b)
{
return a + b;
}
int main()
{
int a = 4;
int b = 4;
cout << add(a, b) << endl;
}
运行结果为:
我们知道上面代码不管传递引用还是传值都没有问题。
我们对于上面代码进行修改:
#include <iostream>
using namespace std;
int add(int & a, int & b)
{
return a + b;
}
int main()
{
int a = 4;
int b = 4;
cout << add(a, b) << endl;
cout << add(4, 5) << endl;
}
那么上面代码就出现了问题:
因为4,5为常量,引用的时候是不允许把const int 常量引用为int 变量。
那么我们就需要在子函数形参加上const:
#include <iostream>
using namespace std;
int add(const int & a, const int & b)
{
return a + b;
}
int main()
{
int a = 4;
int b = 4;
cout << add(a, b) << endl;
cout << add(4, 5) << endl;
}
运行结果为:
那么如果我还想要通过函数进行值的修改,使用const就不能修改,
那我们就使用const重载,在想要修改值的时候就可以进行修改,不想要修改值的时候就不修改:
#include <iostream>
using namespace std;
int add(int& a, int& b)
{
cout << "not const" << endl;
return a + b;
}
int add(const int & a, const int & b)
{
cout << "const" << endl;
return a + b;
}
int main()
{
int a = 4;
int b = 4;
cout << add(a, b) << endl;
cout << add(4, 5) << endl;
}
我们打印出调用函数的不同:
运行结果为:
上面就是使用了const重载。
C++类中的const重载
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void foo()
{
cout << "void foo()" << endl;
cout << _x << endl;
cout << _y << endl;
}
void foo() const
{
cout << "void foo() const" << endl;
cout << _x << endl;
cout << _y << endl;
}
private:
int _x;
const int _y;
};
int main()
{
A a(3,4);
a.foo();
return 0;
}
运行结果为:
如果我们把void foo()函数进行注释:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
//void foo()
//{
// cout << "void foo()" << endl;
// cout << _x << endl;
// cout << _y << endl;
//}
void foo() const
{
cout << "void foo() const" << endl;
cout << _x << endl;
cout << _y << endl;
}
private:
int _x;
const int _y;
};
int main()
{
A a(3,4);
a.foo();
return 0;
}
运行结果为:
我们得出结论:
const构成的重载函数,非const对象调用,优先调用非const函数。
我们对于代码进行修改:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void foo()
{
cout << "void foo()" << endl;
cout << _x << endl;
cout << _y << endl;
}
void foo() const
{
cout << "void foo() const" << endl;
cout << _x << endl;
cout << _y << endl;
}
private:
int _x;
const int _y;
};
int main()
{
const A a(3,4);
a.foo();
return 0;
}
运行结果为:
我们把const类内函数进行注释:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void foo()
{
cout << "void foo()" << endl;
cout << _x << endl;
cout << _y << endl;
}
//void foo() const
//{
// cout << "void foo() const" << endl;
// cout << _x << endl;
// cout << _y << endl;
//}
private:
int _x;
const int _y;
};
int main()
{
const A a(3,4);
a.foo();
return 0;
}
上面代码会编译出错。
我们得到结论:
const 修饰的对象,只能调用类内cosnt成员函数。
很多库常见提供两个版本
const inline static关键字使用注意
const
const 修饰的类内成员函数如果在class外进行实现的时候const也不能省略:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void foo();
void foo() const;
private:
int _x;
const int _y;
};
void A::foo()
{
cout << "void foo()" << endl;
cout << _x << endl;
cout << _y << endl;
}
void A::foo() const
{
cout << "void foo() const" << endl;
cout << _x << endl;
cout << _y << endl;
}
int main()
{
const A a(3,4);
a.foo();
return 0;
}
const 关键在在声明和定义的时候都不能省略
static
static 关键字,只能在类内函数声明的时候出现,定义的时候不允许出现:
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
static void foo();
private:
int _x;
const int _y;
};
void A::foo()
{
}
int main()
{
const A a(3,4);
a.foo();
return 0;
}
上面代码编译可以通过。
inline
inlint 类型关键字可以在函数声明处有,函数定义处没有。可以在函数声明处没有,在函数定义处有。也可以在函数声明和定义的时候都出现。当然,在函数声明和实现的地方都不出现那就和inline没有关系了。
const修饰对象
const 修饰对象,保证在对象层面,不会修改数据成员。所以 const 对象,只能调用 const 成员函数。不同编译器,可能会要求必须自实现构造器,因为若采用默认的话,const 对象的中成员,再无初始化的机会。
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void dis()
{
cout << _x << _y << endl;
}
private:
int _x;
int _y;
};
int main()
{
const A a(3,4);
a.dis();
return 0;
}
上面代码编译会出现错误。
const修饰的对象,其内可以有非const数据成员,但是数据成员不可修改,只能调用const成员函数。
一般来说const修饰对象会提供const和非const两个版本,构成const重载
#include <iostream>
using namespace std;
class A
{
public:
A(int i,int j):_x(i), _y(j)
{}
void dis() const
{
cout << _x << _y << endl;
}
void dis()
{
cout << _x << _y << endl;
}
private:
int _x;
int _y;
};
void func(const A & a)
{
a.dis();
}
int main()
{
const A a(3,4);
a.dis();
func(a);
return 0;
}
运行结果为: