在C++中,explicit
是一个关键字,用于在类定义中显式声明只允许显式转换的构造函数。它的主要作用是防止编译器进行隐式类型转换。
通常情况下,如果一个构造函数只有一个参数,并且没有使用explicit
关键字进行声明,那么编译器在需要进行隐式类型转换时会自动调用该构造函数。这种隐式类型转换有时可能会导致意外的行为或潜在的错误。
通过使用explicit
关键字,我们可以明确指示编译器只能使用显式调用来调用该构造函数,而不允许隐式转换。这样可以增加代码的可读性和明确性,并避免一些潜在的错误。
以下是一个示例,说明explicit
关键字的使用:
class MyClass {
public:
explicit MyClass(int x) {
// 构造函数代码
}
};
void foo(MyClass obj) {
// 函数体
}
int main() {
MyClass obj1(5); // 正确:使用显式构造函数
MyClass obj2 = 10; // 错误:禁止隐式类型转换
MyClass obj3 = MyClass(15); // 正确:使用显式构造函数
foo(obj1); // 正确:隐式调用构造函数
foo(20); // 错误:禁止隐式类型转换
return 0;
}
在上面的例子中,MyClass
的构造函数使用了explicit
关键字进行声明。因此,在创建MyClass
对象时,必须使用显式构造函数调用,而不允许使用隐式类型转换。当我们尝试使用隐式类型转换创建对象时,编译器会报错。
需要注意的是,explicit
关键字只能用于单参数的构造函数,它不能用于多参数的构造函数或其他类型的函数。
如果等号的左边是对象类型,右边恰好是对象的构造函数所需要的类型,这时编译器会自动的把右边的值,放到构造函数中,创建对象。相当于隐式的调用了构造函数
#include
#include
#include
using namespace std;
class Cow{
string name;
public:
Cow(string c);
};
Cow::Cow(string c){
name=c;
cout<<name<<"诞生了!"<<endl;
}
int main()
{
Cow c1("小花");
string s="小黑";
Cow c2=s; //隐式调用了构造函数
}
有时候在赋值的过程中,会不小心隐式调用了构造函数创建了对象,产生问题。为了屏蔽这一现象,需要用到explicit关键字屏蔽隐式构造。
#include
#include
#include
using namespace std;
class Cow{
string name;
public:
explicit Cow(string c); //explicit屏蔽隐式构造调用
};
Cow::Cow(string c){
name=c;
cout<<name<<"诞生了!"<<endl;
}
int main()
{
Cow c1("小花");
string s="小黑";
//Cow c2=s; //不允许隐式调用
}
在C++中,this
是一个特殊的指针,它指向当前对象的地址。它被隐式地传递给每个成员函数(包括构造函数和析构函数),以便在函数内部可以访问当前对象的成员变量和成员函数。
当调用一个对象的成员函数时,编译器会自动将该对象的地址作为this
指针传递给成员函数。通过this
指针,我们可以在成员函数内部访问当前对象的成员变量和成员函数。
下面是一个示例,说明this
指针的使用:
class MyClass {
private:
int x;
public:
void setX(int value) {
this->x = value; // 使用this指针访问成员变量
}
int getX() {
return this->x; // 使用this指针返回成员变量的值
}
};
int main() {
MyClass obj;
obj.setX(5);
int value = obj.getX();
// 此时value的值为5,因为setX将对象obj的成员变量x设置为5,getX返回该值
return 0;
}
在上面的例子中,setX
函数和getX
函数使用了this
指针来访问成员变量x
。通过this->x
,我们可以确保访问的是当前对象的成员变量。
需要注意的是,在成员函数中可以省略this->
,直接使用成员变量的名称访问。例如,上述示例中的代码也可以写成x = value;
和return x;
,编译器会自动将其解析为this->x
。但是,在某些情况下,为了明确表示使用的是成员变量,显式使用this
指针是有益的。
另外,this
指针是一个常量指针,指向的地址不能被修改。因此,我们不能对this
指针进行赋值或修改。
总之,this
指针在C++中用于在成员函数内部引用当前对象,方便访问对象的成员变量和成员函数。
this指针是个特殊的指针,存储的是对象的首地址
#include
#include
#include
using namespace std;
class Test{
public:
void test_this(){
cout<<this<<endl;
}
};
int main()
{
Test t;
cout<<&t<<endl; //0x61fe8f
t.test_this();//0x61fe8f
}
在C++中,每个对象都有一个隐藏的指针叫做this
指针。this
指针指向当前对象的地址,它在成员函数中被隐式地传递,以便在函数内部可以访问当前对象的成员变量和成员函数。
this
指针的原理可以通过编译器的实现来理解。当调用一个对象的成员函数时,编译器在内部做了以下工作:
将对象的地址作为隐式参数传递给成员函数。这是通过在成员函数的调用中插入额外的参数(即this
指针)来实现的。
在成员函数的内部,编译器将通过this
指针来访问对象的成员变量和成员函数。编译器会将成员变量的访问转换为对this
指针的偏移量进行访问。
具体来说,编译器会将成员函数的定义与对象的数据成员进行关联。当成员函数引用成员变量时,编译器会使用this
指针和成员变量的偏移量来计算出实际的内存地址,然后进行读取或写入操作。
需要注意的是,this
指针是一个常量指针,它的值在成员函数执行期间保持不变。因此,this
指针不能被重新赋值或修改其指向的对象。
下面是一个简化的示例,说明this
指针的原理:
class MyClass {
private:
int x;
public:
void setX(int value) {
this->x = value; // 访问成员变量x
}
};
int main() {
MyClass obj;
obj.setX(5);
return 0;
}
在上述示例中,当调用setX
函数时,编译器会将对象obj
的地址作为隐式参数传递给setX
函数,并使用this
指针来访问obj
的成员变量x
。
总结起来,this
指针是一个隐式传递的指针,指向当前对象的地址。它使得成员函数能够访问当前对象的成员变量和成员函数。编译器通过将this
指针作为隐式参数传递给成员函数,并使用偏移量来访问成员变量,实现了this
指针的功能。
类中的成员都是需要对象来调用,对象中函数会有一个隐藏的this指针,代表当前对象。
哪个对象调用的函数,this指针就指向的哪个对象,this指针是编译器自动加的,可以不手动写出
#include
#include
#include
using namespace std;
class Student{
private:
string name;
public:
Student(string n){
this->name=n;
}
void show(){
cout<<this->name<<endl;
}
};
int main()
{
Student s("小强");
s.show();
}
this
指针在C++中有多种应用,它可以用于以下情况:
访问当前对象的成员变量和成员函数:通过this
指针,成员函数可以访问当前对象的成员变量和成员函数。这是this
指针最常见的用法。
class MyClass {
private:
int x;
public:
void setX(int value) {
this->x = value; // 使用this指针访问成员变量x
}
int getX() {
return this->x; // 使用this指针返回成员变量x的值
}
};
解决命名冲突:当成员函数的参数名或局部变量名与成员变量名相同时,可以使用this
指针来明确指示使用的是成员变量而不是参数或局部变量。
class MyClass {
private:
int x;
public:
void setX(int x) {
this->x = x; // 使用this指针访问成员变量x,区分参数和成员变量
}
};
在成员函数中返回对象本身:在链式调用或方法串联的情况下,可以使用this
指针返回对象本身,从而实现连续的函数调用。
class MyClass {
private:
int x;
public:
MyClass& setX(int value) {
this->x = value;
return *this; // 使用this指针返回对象本身,支持链式调用
}
};
MyClass obj;
obj.setX(5).setX(10).setX(15); // 连续调用setX函数
需要注意的是,this
指针是隐式传递的,通常不需要显式地使用它。在大多数情况下,编译器会自动处理this
指针的传递和使用。
另外,需要注意避免在构造函数和析构函数中访问this
指针,因为在对象构造和销毁的过程中,对象的生命周期可能不完整,可能导致不确定的行为。
如果类中的成员变量和参数同名的情况下,需要使用this指针进行区分
#include
#include
#include
using namespace std;
class Student{
private:
string name;
public:
Student(string name){
this->name=name;
}
void show(){
cout<<name<<endl;
}
};
int main()
{
Student s("小强");
s.show();
}
返回值是对象的引用的时候,需要返回*this。this是当前对象的首地址,*this是得到当前对象
#include
using namespace std;
class Value{
private:
int value;
public:
Value(int value){
this->value=value;
}
Value& addValue(int n){
cout<<"当前对象的地址:"<<this<<endl;
this->value+=n;
return * this;
}
void get_value(){
cout<<value<<endl;
}
};
int main()
{
Value v(5);
v.addValue(5);
v.get_value(); //10
//链式调用
v.addValue(10).addValue(10).addValue(10);
v.get_value();
}
在C++中,static
是一个关键字,它用于指定静态成员或静态变量,以及在函数中指定静态局部变量。static
关键字可以应用于以下几个方面:
静态成员变量:在类中声明的静态成员变量属于类本身,而不是类的每个实例。静态成员变量只有一份拷贝,被所有类的实例共享。
class MyClass {
public:
static int count; // 静态成员变量
MyClass() {
count++; // 每次创建对象时,静态成员变量加1
}
};
int MyClass::count = 0; // 静态成员变量的定义和初始化
int main() {
MyClass obj1;
MyClass obj2;
cout << MyClass::count << endl; // 输出:2,因为创建了两个对象
return 0;
}
静态成员函数:静态成员函数属于类本身,而不是类的实例。它们可以直接通过类名调用,无需创建类的实例。
class MyClass {
public:
static void printMessage() {
cout << "This is a static member function." << endl;
}
};
int main() {
MyClass::printMessage(); // 直接通过类名调用静态成员函数
return 0;
}
静态局部变量:在函数内部声明的静态局部变量在程序执行期间保持其值,不会在函数调用结束后被销毁。静态局部变量只在第一次进入函数时进行初始化,并且在后续调用中保持其值。
void myFunction() {
static int counter = 0; // 静态局部变量
counter++;
cout << "Counter: " << counter << endl;
}
int main() {
myFunction(); // 输出:Counter: 1
myFunction(); // 输出:Counter: 2
return 0;
}
静态成员和静态局部变量在内存中分配一份固定的空间,并且可以在不创建类的实例或多次调用函数的情况下使用。它们的生命周期与程序的执行周期相关。
需要注意的是,静态成员变量和静态成员函数可以通过类名直接访问,而无需创建类的实例。然而,它们无法访问非静态成员变量和非静态成员函数,因为非静态成员是与类的实例相关联的。
概念:static修饰的局部变量就称为静态局部变量
特点:
1。静态局部变量在第一次调用的时候创建,只创建一次,在程序运行结束后销毁,作用范围在两个花括号之间。
2.静态局部变量被类中所有对象共享
#include
using namespace std;
class Test{
public:
void test(){
int a=1;
static int b=1; //静态局部变量
a++;
b++;
cout<<a<<" "<<b<<endl;
}
};
int main()
{
Test t;
t.test(); //2 2
t.test(); //2 3
t.test(); //2 4
Test t2;
t2.test(); //2 5
}
用static关键字修饰的成员变量叫静态成员变量
特点:
1.类中所有对象共享静态成员变量
2.非const的静态成员变量,必须类中声明,类外定义。分离的时候,static关键字只需要加在声明处
3.静态成员变量不具体作用于某一对象。它是和类相关的。可以通过类::静态成员变量方式访问。更推荐这种方式
4.在类加载时创建,程序运行结束后才会销毁
#include
using namespace std;
class Test{
public:
static int a;
};
int Test::a=1;
int main()
{
cout<<Test::a<<endl; //不和具体对象相关,可以通过类名::访问
Test t;
cout<<t.a<<endl;
cout<<&(t.a)<<endl; //0x408004
Test t2;
cout<<&(t2.a)<<endl; //0x408004
}
定义:static修饰的成员函数叫静态成员函数
特点:
1.静态成员函数不可以访问非静态的成员。非静态成员访问需要this指针,而静态函数没有this指针
2.非静态成员函数可以访问静态成员
3.静态成员函数声明和定义分离时,static关键字只需加在声明处
#include
using namespace std;
class Test{
private:
static int a;
int b=10;
public:
void method(){
cout<<a<<endl;
cout<<b<<endl;
}
static void static_method(){
cout<<a<<endl;
//cout<
//method(); //静态成员函数不可以访问普通成员方法
}
static void static_method2(); //静态函数类中声明
};
int Test::a=1;
void Test::static_method2(){ //静态函数类外定义
cout<<a<<endl;
}
int main()
{
Test t;
t.static_method();
Test::static_method2();
}
类中普通成员变量是需要创建对象的时候进行初始化。而静态成员函数在对象创建之前就可以访问。如果此时对象没有创建,变量的值随机的,访问没有意义。
静态成员是为了取代c语言中的全局变量和全局函数。让与类紧密相关的全局变量和全局函数写在类里面,形式上形成一个整体。
#include
using namespace std;
class Rectangele{
private:
static int totalNum; //静态成员变量 代表教室总个数
static double totalArea; //代表教室总面积
int width,length;//width代表宽 length代表长
public:
Rectangele(int w,int l);
static void print();
};
int Rectangele::totalNum=0;
double Rectangele::totalArea=0;
Rectangele::Rectangele(int w,int l){ //构造函数类外定义
width=w;
length=l;
totalNum++; //每新建一个对象 教室总个数和面积都会变化
totalArea+=w*l;
}
void Rectangele::print(){
cout<<"教室个数:"<<totalNum<<" 教室总面积:"<<totalArea<<endl;
}
int main()
{
Rectangele r1(20,10);
Rectangele r2(30,10);
Rectangele r3(40,10);
Rectangele::print();
}
在C++中,const
是一个关键字,用于指定常量。const
关键字可以应用于以下几个方面:
常量变量:通过在变量声明前加上const
关键字,可以创建一个常量,即其值在初始化后不能被修改。
const int MAX_VALUE = 100;
MAX_VALUE = 200; // 错误:常量值不能被修改
常量引用:通过将引用声明为const
,可以创建一个只读的引用,即无法通过该引用修改所引用的对象。
int x = 10;
const int& ref = x;
ref = 20; // 错误:无法通过常量引用修改对象的值
常量成员函数:在类中声明的成员函数可以被标记为const
,表示该函数不会修改类的成员变量。
class MyClass {
private:
int x;
public:
void setX(int value) {
x = value;
}
int getX() const {
return x; // 在常量成员函数中,只能访问成员变量,不能修改它们
}
};
常量对象:可以将对象声明为const
,表示该对象在创建后不能被修改。
const MyClass obj; // 声明一个常量对象
obj.setX(10); // 错误:无法通过常量对象调用非常量成员函数
const
关键字的作用是增加程序的可读性、安全性和效率。通过使用const
关键字,我们可以明确指示某些变量或函数的不可变性,避免意外的修改,以及在编译期间进行一些优化。
需要注意的是,const
对象和常量成员函数只能访问类的成员变量,不能修改它们。如果在常量成员函数中对成员变量进行修改,或者通过常量对象调用非常量成员函数,将会导致编译错误。
总结起来,const
关键字在C++中用于指定常量变量、常量引用、常量成员函数和常量对象。它提供了一种机制来确保变量或函数的不可变性,并提高程序的可靠性和可优化性。
const修饰成员函数就叫常成员函数
1.常成员函数可以访问非const成员变量,但是不可以修改其值
2.常成员函数不可以访问非const成员函数的,因为非const成员函数有可能修改属性值
#include
using namespace std;
class Test{
public:
int a=10;
void show2(){
a++;
cout<<a<<endl;
}
void const_show() const{
//a++; //函数只读 不允许修改值
cout<<a<<endl;
//show2(); //不允许访问非const成员函数
}
};
int main()
{
Test t2;
t2.const_show();
t2.show2(); //11
}
用const修饰的对象叫常对象
常对象的特点:
1.不允许更改对象中的任何属性值
2.常对象不允许访问非const函数
const修饰对象可以在类名前,也可以写在类名后
#include
using namespace std;
class Test{
public:
int a=10;
void show2(){
a++;
cout<<a<<endl;
}
void const_show() const{
cout<<a<<endl;
}
};
int main()
{
const Test t1;
Test const t2;
t1.const_show();
t2.const_show();
//t1.show2(); //不允许访问非const成员函数
}
const修饰的成员变量,就叫常成员变量
常成员变量的特点:
1.运行的时候其数值不可以更改
2.初始化的方式,需要通过构造初始化列表或者直接赋值。不能在构造函数体中赋值
#include
using namespace std;
class Test{
private:
const int a=10;
const int b;
public:
Test(int t):b(t){};//初始化列表方式赋值
//不可以通过构造函数赋值
// Test(int t1,int t2){
// a=t1;
// b=t2;
// }
void show(){
//a++; //错误不可以更改其值
cout<<a<<" "<<b<<endl;
}
};
int main()
{
Test t(20);
t.show();
Test t(30,40);
}
不想让函数修改参数数值时,可以加const修饰函数的参数
#include
using namespace std;
class Test{
public:
void test(const int a){
//a++; //const修饰的局部变量 不允许修改值
cout<<a<<endl;
}
};
int main()
{
Test t;
t.test(10);
}