C++ 面向对象基础(下)(嵌入式学习)

C++ 面向对象基础(下)

  • 1. explicit关键字
    • JY
  • 2. this指针
    • 2.1 概念
      • JY
    • 2.2 this指针的原理
      • JY
    • 2.3 this的应用
      • JY
        • 成员变量和参数同名时
        • 返回值是对象引用时
  • 3. static关键字
    • JY
      • 3.1 静态局部变量
      • 3.2 静态成员变量
      • 3.3 静态成员函数
      • 3.4 总结
  • 4. const关键字
    • 4.1 常成员函数
    • 4.2 常对象
    • 4.3 常成员变量
    • 4.4 const修饰局部变量

1. explicit关键字

在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关键字只能用于单参数的构造函数,它不能用于多参数的构造函数或其他类型的函数。

JY

如果等号的左边是对象类型,右边恰好是对象的构造函数所需要的类型,这时编译器会自动的把右边的值,放到构造函数中,创建对象。相当于隐式的调用了构造函数

#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; //不允许隐式调用

}

2. this指针

2.1 概念

在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++中用于在成员函数内部引用当前对象,方便访问对象的成员变量和成员函数。

JY

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

}

2.2 this指针的原理

在C++中,每个对象都有一个隐藏的指针叫做this指针。this指针指向当前对象的地址,它在成员函数中被隐式地传递,以便在函数内部可以访问当前对象的成员变量和成员函数。

this指针的原理可以通过编译器的实现来理解。当调用一个对象的成员函数时,编译器在内部做了以下工作:

  1. 将对象的地址作为隐式参数传递给成员函数。这是通过在成员函数的调用中插入额外的参数(即this指针)来实现的。

  2. 在成员函数的内部,编译器将通过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指针的功能。

JY

类中的成员都是需要对象来调用,对象中函数会有一个隐藏的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();

}

2.3 this的应用

this指针在C++中有多种应用,它可以用于以下情况:

  1. 访问当前对象的成员变量和成员函数:通过this指针,成员函数可以访问当前对象的成员变量和成员函数。这是this指针最常见的用法。

    class MyClass {
    private:
        int x;
    
    public:
        void setX(int value) {
            this->x = value;  // 使用this指针访问成员变量x
        }
    
        int getX() {
            return this->x;  // 使用this指针返回成员变量x的值
        }
    };
    
  2. 解决命名冲突:当成员函数的参数名或局部变量名与成员变量名相同时,可以使用this指针来明确指示使用的是成员变量而不是参数或局部变量。

    class MyClass {
    private:
        int x;
    
    public:
        void setX(int x) {
            this->x = x;  // 使用this指针访问成员变量x,区分参数和成员变量
        }
    };
    
  3. 在成员函数中返回对象本身:在链式调用或方法串联的情况下,可以使用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指针,因为在对象构造和销毁的过程中,对象的生命周期可能不完整,可能导致不确定的行为。

JY

成员变量和参数同名时

如果类中的成员变量和参数同名的情况下,需要使用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();
}

3. static关键字

在C++中,static是一个关键字,它用于指定静态成员或静态变量,以及在函数中指定静态局部变量。static关键字可以应用于以下几个方面:

  1. 静态成员变量:在类中声明的静态成员变量属于类本身,而不是类的每个实例。静态成员变量只有一份拷贝,被所有类的实例共享。

    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;
    }
    
  2. 静态成员函数:静态成员函数属于类本身,而不是类的实例。它们可以直接通过类名调用,无需创建类的实例。

    class MyClass {
    public:
        static void printMessage() {
            cout << "This is a static member function." << endl;
        }
    };
    
    int main() {
        MyClass::printMessage();  // 直接通过类名调用静态成员函数
    
        return 0;
    }
    
  3. 静态局部变量:在函数内部声明的静态局部变量在程序执行期间保持其值,不会在函数调用结束后被销毁。静态局部变量只在第一次进入函数时进行初始化,并且在后续调用中保持其值。

    void myFunction() {
        static int counter = 0;  // 静态局部变量
    
        counter++;
        cout << "Counter: " << counter << endl;
    }
    
    int main() {
        myFunction();  // 输出:Counter: 1
        myFunction();  // 输出:Counter: 2
    
        return 0;
    }
    

静态成员和静态局部变量在内存中分配一份固定的空间,并且可以在不创建类的实例或多次调用函数的情况下使用。它们的生命周期与程序的执行周期相关。

需要注意的是,静态成员变量和静态成员函数可以通过类名直接访问,而无需创建类的实例。然而,它们无法访问非静态成员变量和非静态成员函数,因为非静态成员是与类的实例相关联的。

JY

3.1 静态局部变量

概念: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
}

3.2 静态成员变量

用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
}

3.3 静态成员函数

定义: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();
}

3.4 总结

类中普通成员变量是需要创建对象的时候进行初始化。而静态成员函数在对象创建之前就可以访问。如果此时对象没有创建,变量的值随机的,访问没有意义。
静态成员是为了取代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();
}

4. const关键字

在C++中,const是一个关键字,用于指定常量。const关键字可以应用于以下几个方面:

  1. 常量变量:通过在变量声明前加上const关键字,可以创建一个常量,即其值在初始化后不能被修改。

    const int MAX_VALUE = 100;
    MAX_VALUE = 200;  // 错误:常量值不能被修改
    
  2. 常量引用:通过将引用声明为const,可以创建一个只读的引用,即无法通过该引用修改所引用的对象。

    int x = 10;
    const int& ref = x;
    ref = 20;  // 错误:无法通过常量引用修改对象的值
    
  3. 常量成员函数:在类中声明的成员函数可以被标记为const,表示该函数不会修改类的成员变量。

    class MyClass {
    private:
        int x;
    
    public:
        void setX(int value) {
            x = value;
        }
    
        int getX() const {
            return x;  // 在常量成员函数中,只能访问成员变量,不能修改它们
        }
    };
    
  4. 常量对象:可以将对象声明为const,表示该对象在创建后不能被修改。

    const MyClass obj;  // 声明一个常量对象
    obj.setX(10);  // 错误:无法通过常量对象调用非常量成员函数
    

const关键字的作用是增加程序的可读性、安全性和效率。通过使用const关键字,我们可以明确指示某些变量或函数的不可变性,避免意外的修改,以及在编译期间进行一些优化。

需要注意的是,const对象和常量成员函数只能访问类的成员变量,不能修改它们。如果在常量成员函数中对成员变量进行修改,或者通过常量对象调用非常量成员函数,将会导致编译错误。

总结起来,const关键字在C++中用于指定常量变量、常量引用、常量成员函数和常量对象。它提供了一种机制来确保变量或函数的不可变性,并提高程序的可靠性和可优化性。

4.1 常成员函数

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
}

4.2 常对象

用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成员函数
}

4.3 常成员变量

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);
}

4.4 const修饰局部变量

不想让函数修改参数数值时,可以加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);
}

你可能感兴趣的:(嵌入式学习,c++,学习,开发语言)