C++:类和对象

发布于:2025-09-11 ⋅ 阅读:(13) ⋅ 点赞:(0)

   

一、类和对象的定义

        C++ 在 C 语言的基础上增加了面向对象编程,C++ 支持面向对象程序设计。类是 C++
的核心特性,通常被称为用户定义的类型。类用于指定对象的形式,它包含了数据表示法和用
于处理数据的方法。类中的数据和方法称为类的成员。函数在一个类中被称为类的成员。


        打个比方说明一下什么是类,比如有一条小狗,小狗有名字叫旺财,旺财的年龄是 2 岁,
同时旺财会汪汪的叫,也能跑。我们统称狗这个为类,类是我们抽象出来的,因为狗不只有上
面的属性,还有体重,毛发的颜色等等,我们只抽象出几种属性成一个类。具体到哪条狗就叫
对象。
        从类中实例化对象分两种方法,一种是从栈中实例化对象,一种是从堆中实例化对象。

        类是创建对象的模板,一个类可以创建多个对象,每个对象都是类类型的一个变量;创建对象的过程也叫做类的实例化。

类的定义

class   类名{

public:

  公有的数据;

protected:

  保护的数据;

private:

  私有的数据;};

        C++通过 publicprotectedprivate 三个关键字来控制成员变量和成员函数的访问权限,它们分别表示公有的、受保护的、私有的,被称为成员访问限定符。所谓访问权限,就是你能不能使用该类中的成员。

#include <iostream>

using namespace std;

class Dog
{

public://不写关键字的时候默认是private属性
    string name;
    int age;
    void run()
    {
        cout<<"狗会跑"<<endl;
    }
private:
    double weight;
};


int main()
{
    //从栈中实例化对象
    Dog dog1;
    dog1.name = "旺财";
    cout<<dog1.name<<endl;
    dog1.run();

    //dog1.weight = 50.2;
    //private和protect下面的成员类的对象无法访问

    //从堆中实例化对象,要用delete删除
    //不用delete删除的话,程序结束后系统会回收
    //不删除对象的话,这个指针会占这内存不放,会造成内存泄漏
    Dog* dog2 = new Dog;
    dog2->age = 3;
    cout<<dog2->age<<endl;
    delete  dog2;
    return 0;
}

/*    输出:
旺财
狗会跑
3
*/

二、构造函数和析构函数

        定义了一个名称和类名相同,没有返回值的函数,这个函数称为构造函数。构造函数的特殊之处在于,它会在类实例化的时候被调用。

#include <iostream>
class Dog
{
public:
    Dog();
};

对象实例化的时候,会调用构造函数,而对象销毁的时候,就会调用析构函数。

        对象销毁:程序结束了由系统释放;删除指针对象的时候

#include <iostream>
class Dog
{
public:
    ~Dog();
};

举个栗子1:

#include <iostream>

using namespace std;

class Dog
{
public:
    Dog(){
        cout<<"构造函数被执行了"<<endl;
    }
    ~Dog();

};
Dog::~Dog()
{
    cout<<"析构函数被执行了"<<endl;
}

int main()
{
    Dog dog1;
    return 0;
}

举个栗子2:

#include <iostream>

using namespace std;

class Dog
{
public:
    Dog(){
        cout<<"构造函数被执行了"<<endl;
    }
    ~Dog();

};
Dog::~Dog()
{
    cout<<"析构函数被执行了"<<endl;
}

int main()
{
    //Dog dog1;
    Dog*dog2 =new Dog;
    return 0;
}

栗子1输出:                                                                 栗子2输出:
构造函数被执行了                                                        构造函数被执行了
析构函数被执行了

        栗子1是从栈中实例化对象,程序结束了系统会回收对象

        栗子2中析构函数没有执行,因为堆中实例化对象要用delete删除,栗子2中的对象没有被销毁

        在类实例化对象的时候,如果没有定义构造函数,则编译器会合成一个默认的构造函数;当有了对象后,如果没有定义析构函数,则编译器会合成一个默认的析构函数。

三、this指针

        this指针装着当前对象的地址,即每个对象都有自己的地址,我们可通过&t1,&t2...(对对象取地址)获取到各个对象的地址,C++在类内直接提供了地址,我们就不需要在类外获取了。C++面向对象编程提供了一个变量叫做this指针,该地址自动初始化成我们当前对象的地址,我们可以在类内直接使用this指针,就可使用当前对象的地址了。

        这时候我们会想到,我直接取对象的地址,通过函数传递到类的内部去使用,为什么还存在this指针呢?这就是C++面向对象编程的思想了,对象表面是个变量,实际上它是区别于变量int、double等等,对象是拥有一个丰富功能的一个完整个体,一个对象自身就知道自己的地址,不需要“别人告诉”。

        每个成员函数:析构、构造、自定义函数,都可以使用this指针,this指针作为函数的隐藏参数,传递给函数,每个成员都有,this的实现方法暂不研究。

        this指针可用于区分类成员和局部变量        

#include <iostream>
using namespace std;

class Test
{
private:
    //Test*this; "相当于类"内有this变量
    int a;
public:
    Test(/* Test*this ,*/int a)
    {
        this->a = a;  //用处1:区分 类成员和函数参数的局部变量

    }
    void Print(){

        cout<<a<<' '<<this<<endl;
    }
};

int main()
{
    Test t(12);
    t.Print();
    cout<<"&t:"<<&t<<endl;
    return 0;
    /*
        输出:
     
        12 0x7fff76e94494
        &t:0x7fff76e94494

      */
}

        this指针可用于以下栗子:

#include <iostream>
using namespace std;

class Test
{
private:
    //Test*this; "相当于类"内有this变量
    int a;
public:
    Test(/* Test*this ,*/int a)
    {
        //this->a = a;  //用处1:区分 类成员和函数参数的局部变量
        (*this).a = a;
    }
    void Print(){

        cout<<a<<' '<<this<<endl;
    }
    Test*GetAddr(){

        return this;    //用处3:返回当前对象的地址,外部使用
    }
    Test& GetObject()
    {
        return *this;   //用处4:this是对象的地址,*this是对象本身
    }

};

int main()
{
    Test t(120);
    cout<<t.GetAddr()<<endl;//&t
     t.GetObject().Print() ;
    return 0;
    /*
        输出:
    
        ff2b1a2d14
        120 0x7fff2b1a2d14

      */
}

        

四、类的继承

        创建新类时,并不需要创建全新的数据和成员函数,我们可以指明这个新类继承现有类的成员。此时,现有的类称为“基类”,继承实现的新类称为“派生类”。

举个栗子:子类可以调用父类的成员

#include <iostream>
using namespace std;
//基类/父类
class Animal
{
public:
    string name;
    int age;
    void run()
    {
        cout<<"狗的年龄: "<<age<<endl;

    }
};

//派生类/子类
class Dog:public Animal
{

};

int main()
{
    Dog dog1;
    dog1.age = 5;
    dog1.run();

    return 0;
}
       (1)公有继承时基类中各成员属性保持不变,基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象只能访问基类中的public成员。
        下面栗子对应派生类的成员不能访问private成员

        (2)保护继承时基类中各成员属性均变为protected,并且基类中private成员被隐藏。派生类的成员只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

        (3)私有继承时基类中各成员属性均变为private,并且基类中private成员被隐藏。派生类的成员也只能访问基类中的public/protected成员,而不能访问private成员;派生类的对象不能访问基类中的任何的成员。

五、函数重载

        在同一个作用域内,声明几个功能类似的同名函数,并且这些同名函数的参数个数、参数类型或者参数顺序不同,那么就叫函数重载。

栗子1:

#include <iostream>

using namespace std;

class Dog
{
public:
    Dog(int weight)//构造函数重载
    {
        cout<<"int 狗的体重:"<<weight<<endl;

    }

    Dog(double weight)//构造函数重载
    {

        cout<<"double 狗的体重:"<<weight<<endl;

    }

};
int main()
{

    Dog dog1(50);
    Dog dog2(50.5)
    return 0;
}

/*    输出:
int 狗的体重:50
double 狗的体重:50.5
*/

栗子2:

#include <iostream>

using namespace std;

class Dog{
public:
    void getWeight(int weight){
        cout<<"int 狗的体重:"<<weight<<endl;
    }
    void getWeight(double weight){
        cout<<"double狗的体重:"<<weight<<endl;
    }
};
int main()
{
    Dog dog1;
    dog1.getWeight(100);
    dog1.getWeight(100.7);
    return 0;
}

        学习更新行中·········


网站公告

今日签到

点亮在社区的每一天
去签到