c++面向对象的基础

面向对象的三大特征: 封装 继承  多态

物以类聚,人与群分

类:同一类事物(对象)共同特征提取出来,就形成了类。类是抽象的概念

对象:由类创建的具体实体

类中包括属性和行为

属性  称为成员变量 或者数据成员

行为  称为成员函数 或者成员方法

成员变量和成员函数 都称为类的成员

1.类的实现

#include 
using namespace std;

class Computer{ //class是类的关键字   Computer是类名
public: //公共权限 ,类内和类外都可以访问
    string brand;
    string model;
    void play_music(){
        cout<<"《只因你太美》"<<endl;
    }
    void play_video(){
        cout<<"《家有儿女》"<<endl;
    }
    void run_game(){
        cout<<"《原神》"<<endl;
    }
    void show(){
        cout<<"品牌:"<<brand<<" 型号:"<<model;
    }
};
int main()
{


}

2.类的实例化

由类创建对象的过程叫类的实例化

对象分为两种:

1.栈内存对象 : 用.运算符调用成员,出了作用范围(两个花括号之间)自动销毁

2.堆内存对象: 用new关键字在堆区创建对象,对象类型的指针指向new关键字开辟的空间。使用->的方式调用成员。堆内存对象需要程序员手动销毁,如果不销毁这块内存区域会被持续占用,造成内存泄漏,造成程序的卡顿。所以需要用delete关键字进行销毁,并把对象指针置为NULL

#include 
using namespace std;

class Computer{ //class是类的关键字   Computer是类名
public: //公共权限  类内和类外都可以访问
    string brand;
    string model;
    void play_music(){
        cout<<"《只因你太美》"<<endl;
    }
    void play_video(){
        cout<<"《家有儿女》"<<endl;
    }
    void run_game(){
        cout<<"《原神》"<<endl;
    }
    void show(){
        cout<<"品牌:"<<brand<<" 型号:"<<model;
    }
};

int main()
{
    //栈内存对象
    Computer c1; //对象名叫c1
    c1.brand="联想";
    c1.model="air14";
    //由对象调用方法
    c1.play_music();
    c1.play_video();
    c1.run_game();
    c1.show();


    //堆内存对象
    Computer * c2=new Computer;
    c2->brand="DELL";
    c2->model="Dell3542";

    c2->play_music();
    c2->play_video();
    c2->run_game();
    c2->show();
    delete c2; //销毁c2指向的堆内存空间 
    c2=NULL;   //把对象指针置为NULL

}

3.封装

概念:通常情况下,会把类中的属性或者特征进行隐藏。通常是把类中的属性变为私有。如果外部访问需要公共接口,可以控制属性的读和写的权限。提高了程序的安全性

私有权限,只有类内可以访问,类的外部访问不到

#include 
using namespace std;
//姓名 name   密码 password   地址 address
class Person{
private: //私有权限,只有类内可以访问
    string name;  //可读 可写
    string password="123456"; //只写
    string address;  //只读
public:
    void getName(){
        cout<<"姓名是:"<<name<<endl;
    }
    void setName(string n){
         name=n;
    }

    void setPassword(string p){
        password=p;
    }
    void getAddress(){
        cout<<"济南"<<endl;
    }
};
int main()
{
    Person p;
    //p.name="小明"; //错误
    p.setName("小明");
    p.setPassword("123789");

    p.getName();
    p.getAddress();
}

4.构造函数

作用:用于创建对象时给属性值进行初始化

构造函数是个特殊的函数:

  1. 无需写返回值,不可以写void
  2. 构造函数与类同名
  3. 如果没有显示给出构造函数,编译器会给出默认的构造函数(参数为空,并且函数体为空)并没有实际操作,如果写出任意构造函数,编译器默认的构造函数就不存在

无参构造函数

#include 
using namespace std;
class Computer{
private:
    string brand;
    string model;
    int weight;
public:
    void show(){
        cout<<brand<<" "<<model<<" "<<weight<<endl;
    }
    //Computer(){}  //编译器默认的构造函数
    Computer(){
        brand="HP";
        model="暗影精灵";
        weight=100;
    }
};
int main()
{
    Computer c1; //没有指定对象参数,会调用无参的构造函数
    c1.show();
}

有参构造函数

有参构造函数让对象的创建更加灵活

#include 
using namespace std;
class Computer{
private:
    string brand;
    string model;
    int weight;
public:
    void show(){
        cout<<brand<<" "<<model<<" "<<weight<<endl;
    }
    //Computer(){}  //编译器默认的构造函数
    Computer(string b,string m,int w){
        brand=b;
        model=m;
        weight=w;
    }

};
int main()
{
    Computer c1("联想","pro16",200); 
    c1.show();
}

构造函数支持函数重载

#include 
using namespace std;
class Computer{
private:
    string brand;
    string model;
    int weight;
public:
    void show(){
        cout<<brand<<" "<<model<<" "<<weight<<endl;
    }
    //构造函数支持重载
    Computer(string b,string m,int w){
        brand=b;
        model=m;
        weight=w;
    }
    Computer(){
        brand="HP";
        model="暗影精灵";
        weight=100;
    }


};
int main()
{
    Computer c1("联想","pro16",200); //调用三个参数的构造函数
    c1.show();

    Computer * c2=new Computer; //调用无参构造函数
    c2->show();
    delete c2;
    c2=NULL;

    Computer * c3=new Computer("联想","air15",150);
    c3->show();
    delete c3;
    c3=NULL;
}

构造函数支持函数默认值

同样遵循函数默认的注意事项

#include 
using namespace std;
class Computer{
private:
    string brand;
    string model;
    int weight;
public:
    void show(){
        cout<<brand<<" "<<model<<" "<<weight<<endl;
    }
    //构造函数支持重载
    Computer(string b="HP",string m="暗影精灵",int w=100){
        brand=b;
        model=m;
        weight=w;
    }

};
int main()
{
    Computer c1("联想","pro16",200); //调用三个参数的构造函数
    c1.show();

    Computer * c2=new Computer; //调用无参构造函数
    c2->show();
    delete c2;
    c2=NULL;

    Computer * c3=new Computer("联想","air15",150);
    c3->show();
    delete c3;
    c3=NULL;
}

构造初始化列表

是构造函数简便写法 ,对象属性简单赋值时推荐初始化列表

#include 
using namespace std;
class MobilePhone{
private:
    string brand;
    string model;
public:
    //构造初始化列表
    MobilePhone(string b,string m):brand(b),model(m){}
    void show(){
        cout<<brand<<" "<<model<<endl;
    }
};
int main()
{
    MobilePhone mp1("苹果","14promax");
    mp1.show();

}

  1. 拷贝构造函数

概念:用已存在对象的值来初始化新的对象属性值

拷贝构造的特点

  1. 拷贝构造函数与构造函数构成重载
  2. 如果不显示写出拷贝构造函数,编译器会给出默认的拷贝构造函数,完成对象之间的值复制。如果显示写出拷贝构造,编译器就不会提供默认的拷贝构造

拷贝构造函数的形式:

  1. 与类同名
  2. 参数是对象的引用或者const修饰对象的引用

对象之间相互独立的,对象之间属性也是相互独立的

#include 
using namespace std;
class MobilePhone{
private:
    string brand;
    string model;
public:

    MobilePhone(string b,string m):brand(b),model(m){}
     //默认的拷贝构造功能与下方类似
    //显示写出拷贝构造函数。编译器就不会给出默认的拷贝构造
    MobilePhone(const MobilePhone& other){
        cout<<"调用拷贝构造函数"<<endl;
        brand=other.brand;
        model=other.model;
    }
    void show(){
        cout<<brand<<" "<<model<<endl;
    }

};
int main()
{
    MobilePhone mp1("苹果","14promax");
    mp1.show();
    cout<<"------------"<<endl;
    MobilePhone mp2(mp1);
    mp2.show();

    cout<<&mp1<<" "<<&mp2<<endl; //0x61fe78 0x61fe70
}

深拷贝和浅拷贝

浅拷贝:编译器默认给出的拷贝构造函数,完成的就是浅拷贝。会完成对象之间简单的值复制。但是如果对象的属性有指针类型时,浅拷贝也只会简单的地址值的复制,这时两个对象的指针保存同一块地址,指向了同一块内存。破坏了对象之间的独立性

浅拷贝

#include 
#include 
using namespace std;
class MobilePhone{
private:
    char * brand;
public:
    MobilePhone(char * n){
        brand=n;
    }
    MobilePhone(const MobilePhone& other){
        brand=other.brand;
    }
    void show(){
        //C++中cout后面跟的char * 会自动打印出字符串的内容
        cout<<brand<<endl;
    }

};
int main()
{
  char a[20]="xiaomi";
  MobilePhone mp1(a); //mp1.brand --->a
  MobilePhone mp2(mp1); //mp2.brand--->a

  mp1.show(); //xiaomi
  mp2.show(); //xiaomi

  strcpy(a,"redmi");
  mp1.show(); //redmi
  mp2.show(); //redmi
}

深拷贝

当对象属性有指针类型时,对象指针变量需要指向自己独立的区域,拷贝内容代替拷贝地址

#include 
#include 
using namespace std;
class MobilePhone{
private:
    char * brand;
public:
    MobilePhone(char * n){
        brand=new char[20];
        strcpy(brand,n);
    }
    MobilePhone(const MobilePhone& other){
        brand=new char[20];
        strcpy(brand,other.brand);
    }
    void show(){
        //C++中cout后面跟的char * 会自动打印出字符串的内容
        cout<<brand<<endl;
    }
};
int main()
{
  char a[20]="xiaomi";
  MobilePhone mp1(a);

  MobilePhone mp2(mp1);
  mp1.show(); //xiaomi
  mp2.show(); //xiaomi

  strcpy(a,"redmi");
  mp1.show(); //xiaomi
  mp2.show(); //xiaomi

}

  1. 析构函数

析构函数:对象销毁前做善后清理工作。在对象销毁时,之前为成员变量开辟的内存空间需要进行释放

形式:  ~类名() {}

析构函数特点

  1. 与类同名 ,因为没有参数,所以不能重载
  2. 不显示给出析构函数,会有默认的析构函数,函数体为空。给出析构函数,编译器就不提供默认析构函数
  3. 对象销毁时自动调用

#include 
#include 
using namespace std;
class Cat{
private:
    string name;
public:
    Cat(string n):name(n){
        cout<<name<<"诞生了"<<endl;
    }
    ~Cat(){
        cout<<name<<"挂掉了"<<endl;
    }

};
void test(){
    Cat c("Tom");
    Cat * c2=new Cat("蓝猫"); //如果不delete销毁,堆对象空间不会释放,会造成内存泄漏
    delete c2;   //delete之后会自动调用析构函数
}
int main()
{
    test();
    cout<<"-----------"<<endl;

}

如果类中都是基本数据类型和string 类型,这时可以不显示写出析构函数,对象的数据会随着对象的销毁而销毁

当类中有指针类型的变量时候,这时需要写出析构函数,释放为指针变量开辟的空间

之前深拷贝,析构完善的代码:

#include 
#include 
using namespace std;
class MobilePhone{
private:
    char * brand;
public:
    MobilePhone(char * n){
        brand=new char[20];
        strcpy(brand,n);
    }
    MobilePhone(const MobilePhone& other){
        brand=new char[20];
        strcpy(brand,other.brand);
    }
    ~MobilePhone(){
        //[]指明,delete的指针指向的是数组形式的
        delete [] brand;
    }
    void show(){
         cout<<brand<<endl;
    }
};
int main()
{
  char a[20]="xiaomi";
  MobilePhone mp1(a);

  MobilePhone mp2(mp1);
  mp1.show(); //xiaomi
  mp2.show(); //xiaomi

  strcpy(a,"redmi");
  mp1.show(); //xiaomi
  mp2.show(); //xiaomi

}

  1. 作用域限定符的使用
    1. 名字空间 

命名空间实际上是由程序设计者命名的内存区域,程序设计者可以根据需要指定一些有名字的空间区域,把一些自己定义的变量、函数等标识符存放在这个空间中,从而与其他实体定义分隔开来。

std是C++标准库的一个名字空间,很多使用的内容都是来自于标准名字空间,例如字符串std::string、std::cout...

当项目中包含using namespace std;时,代码中使用std名字空间中的内容就可以省略前面的std::

#include 
#include 
using namespace std;
int a=20;
namespace mySpace {
    int a=30;
}
int main()
{
    int a=10;
    cout<<a<<endl; //10
    cout<<::a<<endl; //20  ::代表全局
    cout<<mySpace::a<<endl; //30
}

7.2 函数声明和定义分离时

函数声明和定义分离时需要用,类名::  指明函数属于哪个类,指明函数范围

void Student::setAge(int a

void      返回值

Student::    类的作用域限定符

setAge    函数名

#include 
using namespace std;
class Student{
private:  
    string name;
    int age;

public:
    Student(string n,int a);
    void setAge(int a);//类内声明
    int getAge();
};
Student::Student(string n,int a){
   name=n;
   age=a;
}
void Student::setAge(int a){
    age=a;
}
int Student::getAge(){
    return age;
}

int main()
{
    Student s("小强",20);
    cout<<s.getAge()<<endl;

}

  1. explicit关键字

等号赋值时,等号左侧是对象类型,右侧恰好是对象构造函数所需要的类型,这时就会把右侧值传入到构造函数中,相当于隐式调用构造函数。 

但是编码过程中,可能会不小心,隐式触发构造函数。造成错误,所以可以用explicit关键字屏蔽隐式构造

#include 
using namespace std;
class Student{
private:
    string name;
public:
    explicit Student(string n);
    void show();
};
void Student::show(){
    cout<<name<<endl;
}
Student::Student(string n){
   name=n;
}
int main()
{
    Student s("小明");
    s.show();
    string str="小刚";
    //Student s2=str; // 屏蔽隐式构造之后 ,这行就会报错
    //s2.show();

}

  1. this指针

概念

this指针是个特殊的指针,存储是对象的首地址,成员函数都隐含一个this指针

#include 
using namespace std;
class Test{
public:
    void show(){
        cout<<this<<endl;
    }
};
int main()
{
    Test t;
    t.show(); //0x61fe8f
    cout<<&t<<endl; //0x61fe8f

    Test * t2=new Test;
    t2->show();
    cout<<t2<<endl; //0x6f17a8
    delete t2; //0x6f17a8
    t2=NULL;

}

原理

类的成员函数都隐含一个this指针。哪个对象调用成员函数,this指针就指向哪个对象,访问哪个对象的属性。虽然不用手写this指针,但是编译器都会使用this指针来调用成员

#include 
using namespace std;
class Test{
private:
    int a;
public:
    Test(int n){
        this->a=n;
    }
    void show(){
        cout<<this->a<<endl;
    }
    void setA(int n){
        this->a=n;
    }

};

int main()
{
    Test t(10);
    Test t2(20);
    t.show(); //10
    t2.show(); //20
}

this指针应用

1.区分同名参数与属性

可以用this指针来区分属性 和 参数

#include 
using namespace std;
class Student{
private:
    string name;
    int age;

public:
    Student(string n,int a);
    void show();


};
Student::Student(string name,int age){
   name=name; //参数给参数
   age=age;
}
void Student::show(){
    cout<<name<<" "<<age<<endl;
}
int main()
{
    Student s("小强",20);
    s.show();

}

this指针区分属性和参数

#include 
using namespace std;
class Student{
private:
    string name;
    int age;

public:
    Student(string n,int a);
    void show();


};
Student::Student(string name,int age){
   this->name=name; //参数给参数
   this->age=age;
}
void Student::show(){
    cout<<name<<" "<<age<<endl;
}


int main()
{
    Student s("小强",20);
    s.show();

}

2.链式调用

当返回值是对象引用时,可以返回*this ,此函数支持链式调用

#include 
using namespace std;
class Value{
private:
    int n;
public:
    Value(int n){
      this->n=n;
    }
    void getValue(){
       cout<<"结果:"<<n<<endl;
    }
    Value& addValue(int m){ //返回值是对象的引用 
        this->n+=m;
        return *this;
    }
};

int main()
{
    Value v1(10);
    v1.getValue();
    v1.addValue(10).addValue(10).addValue(10);
    v1.getValue(); //40
}

  1. static关键字

静态局部变量

static关键字修饰的局部变量。特点类中所有对象共享,所在函数第一次调用时初始化,程序结束时销毁

#include 
using namespace std;
class Test{
public:
    void testStatic(){
        int a=1;
        static int sa=1;
        cout<<++a<<" "<<++sa<<endl;

    }

};
int main()
{
    Test t;
    t.testStatic(); //2 2
    t.testStatic(); //2 3

    Test t2;
    t2.testStatic();//2 4

}

静态成员变量

static关键字修饰的成员变量

  1. 必须得类内声明,类外初始化
  2. 所有对象共享,程序运行时创建,程序结束时销毁
  3. 公共权限下,除了用对象访问静态成员变量,也可以使用 类名::静态成员变量

#include 
using namespace std;
class Test{
public:
    //static int b=1; 错误
    static int b;
};
int Test::b=1;
int main()
{
    cout<<Test::b<<endl; //1  在对象没存在之前,静态成员变量就已经创建
    Test t1;
    cout<<t1.b<<endl; //1
    t1.b++;
    Test t2;
    cout<<t2.b<<endl; //2

}

静态成员函数

static修饰的成员函数就是静态成员函数。

  1. 对象产生之前就可以调用。而普通成员函数必须需要对象来调用
  2. 静态成员函数只可以访问静态成员,不可以访问非静态成员。因为静态成员函数没有this指针
  3. 静态成员函数声明和定义分离时,static只需加在声明处

#include 
using namespace std;
class Test{
public:
    //static int b=1; 错误
    static int b;
    int a=10;
    void test(){
        cout<<"hello"<<endl;
    }
    //静态函数没有this指针
    static void testStatic(){
        //cout<a<
        //this->test();  //普通成员函数,必须得对象来调用
        cout<<b<<endl;
    }
};
int Test::b=1;
int main()
{
    Test::testStatic(); //1
}

11.const关键字

通常表示只读,不可修改。可以保证数据的安全

常局部变量

const修饰的局部变量。不可修改其数值

#include 
using namespace std;
class Test{
public:
    void func(const int a){
        //a++; 只读不允许修改
        cout<<a<<endl;
    }
};
int main()
{
    Test t;
    int n=10;
    t.func(n);
}

常成员变量

const修饰的成员变量

  1. 运行时其值不可以修改
  2. 必须通过初始化列表赋予初始值,不能通过构造函数方法体中赋值

#include 
using namespace std;
class Test{
private:
    const int constNum;
public:
//普通构造函数不可以给常成员变量初始化
//    Test(int n){
//        constNum=n;
//    }
    Test(int constNum):constNum(constNum){}
    void show(){
        //constNum++; //错误 只读不可以修改
        cout<<constNum<<endl;
    }
};
int main()
{
    Test t(10);
    t.show();

}

常成员函数

const修饰的成员函数

  1. 可以访问非const成员变量,但不可以更改变量值
  2. 不可以访问非const成员函数

#include 
using namespace std;
class Test{

public:
    int a=10;
    void show(){
        cout<<a<<endl;
        a++;
        cout<<a<<endl;
    }
    void show2() const
    {
        cout<<a<<endl;
        //a++; //错误 const修饰的函数中不允许变量值
        //show(); //错误 不可以访问非const函数
    }

};

int main()
{
    Test t;
    t.show();
    t.show2();


}

常对象

const修饰的对象   

第一种方式: const 类名  对象名   

第一种方式:  类名  const  对象名   

常对象不允许修改属性值,只能访问const函数

#include 
using namespace std;
class Test{

public:
    int a=10;
    void show(){
        cout<<a<<endl;
        a++;
        cout<<a<<endl;
    }
    void show2() const
    {
        cout<<a<<endl;
    }

};

int main()
{
    const Test t;
    //t.show();  //错误
    t.show2();

    Test const t2;
    t2.show2();
}

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值