【c++基础】第二章 微观部分:面向对象之类的组成

对象:属性和方法组成,是类的一个实例化

类(class):具有相同属性和方法,是对象的抽象

类的封装性:权限(public/private/protected)+属性+方法

在这里插入图片描述

在这里插入图片描述

类的大小(和结构体相似):

空类,1byte;类对象的大小与类中的非静态属性相关,类对象共享类中的成员函数的地址

练习:

#include <iostream>

using namespace std;

class rectangle{
    int wide;
    int length;
public:
    void setwide(int wide){
        this->wide=wide;
    }
    void setlength(int length){
        this->length=length;
    }

    int getArea(){
        return this->wide*this->length;
    }
};

rectangle& compair(rectangle& r1,rectangle& r2){
    return r1.getArea()>r2.getArea()?r1:r2;
}

int main()
{
    int wide=10;
    int length=20;
    rectangle *rect1=new rectangle();
    rect1->setwide(wide);
    rect1->setlength(length);
    cout << "rectangle's area1 = " << rect1->getArea() << endl;

    wide=20;
    length=30;
    rectangle rect2;
    rect2.setwide(wide);
    rect2.setlength(length);
    cout << "rectangle's area2 = " << rect2.getArea() << endl;

    cout << "---------------------------------------------------" << endl;
    cout << "较大的面积为:" << endl;
    cout << compair(*rect1,rect2).getArea() << endl;

    return 0;
}

函数

类中函数(类的骨架):

  • 构造函数
  • 析构函数
  • 可被构造函数
  • 运算符重载函数
  • 取值运算符
  • 长取值运算符

构造函数

没有任何返回值,函数名与类名相同,由编译器根据对象定义参数决定

  • 不存在,编译器生成一个无参的空构造
  • 存在,编译器不在生成
  • 意义:对类对象属性进行初始化类中get()/set()函数的升级
#include <iostream>

using namespace std;

class stu{
    string name;
    int age;
public:
    stu(){
        cout << "stu的无参构造" << endl;
    }
    stu(string name,int age){ 
        this->name=name;
        this->age=age;
        cout << "stu的有参构造" << endl;
    }
    void showInfo(){
        cout << "姓名:" << this->name << "  年龄:" << this->age << endl;
    }
};

int main()
{
    stu s1;
//    stu s1();//是一个函数声明,并非是无参函数的调用
    stu s2("yao",18);
    s2.showInfo();
    stu *s3=new stu("yaoliang",19);
    s3->showInfo();
    delete s3;
    return 0;
}

显示(explicit)调用和隐式(implicit expression) 调用

#include <iostream>

using namespace std;

class A{
    int a;
public:
    A(){
       cout << "i am is NULL structure" << endl;
    }
    A(int a){
        cout << "i am is single structure" << endl;
    }
    A(int a,int b){
        cout << "i am is more structure" << endl;
    }
    explicit A(int a,int b,int c){
        cout << "i am is more more structure" << endl;
    }
};

int main()
{
    cout << " explicit structure " << endl ;
    A a;
    A a1(1);
    A a2(1,2);
    A a3(1,2,3);
    cout << " implicit  expression strcture" << endl ;
    A a4 = 1;
    A a5 = {1,2};
//    A a6 = {1,2,3};//在类构造函数前加上explicit,无法隐式调用
    return 0;
}

析构函数

在这里插入图片描述

#include <iostream>

using namespace std;

class stu{
    string name;
    int age;
    int *p;
public:
    stu(string name,int age){
        this->name=name;
        this->age=age;
        this->p=new int[1024];
        cout << "stu structure" << endl;
    }
    ~stu(){
        delete []p;
        cout << "stu destruct" << endl;
    }
};

int main()
{
    stu s1("zhangsan",10);
    stu *s2 = new stu("yao",18);
    delete s2;
    return 0;
}

好处:避免内存泄漏,先清理资源,在销毁空间

拷贝构造函数

类中没有提供拷贝构造函数,当出现使用其他对象为本对象进行初始化时,编译器自动生成,以供调用

浅拷贝:

  • 优点:简单赋值,可以提高效率
  • 缺点:指针共享一块内存,析构后,内存被回收

在这里插入图片描述

#include <iostream>

using namespace std;

class stu{
    string _name;
    int _age;
    int *_score;
public:
    stu(string name,int age,int *score)
    {
        this->_name=name;
        this->_age=age;
        this->_score=new int[10] ();
        memcpy(this->_score,score,10);
//        this->_score=score;
        cout << "stu structure" << endl;
    }
    ~stu(){
        delete [] _score;
        cout << "stu destruct" << endl;
    }
    stu(const stu& other){
        this->_name=other._name;
        this->_age=other._age;
//        this->_p=other._p;
        //深拷贝
        this->_score=new int[10];
        memmove(this->_score,other._score,sizeof(int[10]));
        cout << "stu copy" <<endl;
    }
    void showInfo()const{
        cout << "姓名: " << this->_name ;
        cout << "年龄: " << this->_age ;
        cout << "成绩: " << this->_score[0] ;
        cout << endl;
    }

    int getAge()const{
        return this->_age;
    }
};

const stu& compair(const stu& s1,const stu& s2){
    return s1.getAge()>s2.getAge()?s2:s1;
}

//多拷贝3次
//stu compair(stu s1,stu s2){
//    return s1.getAge()>s2.getAge()?s2:s1;
//} 

int main()
{
    int score[10]={100,80,40};
    //显示调用
    stu s1("yaoliang",18,score);
    stu s2(s1);
    s2.showInfo();
    //隐式调用
    stu s3("minmin",17,score);
    stu s4=s3;
    s4.showInfo();

    cout << "-----------stu's age compair ,input small age imformation------------" << endl;
    compair(s2,s4).showInfo();
    return 0;
}

引用可以提高深拷贝的运行效率,使用常引用,保证实参安全

运算符重载函数

面向对象服务全局也可以定义,但类中优先存在深浅拷贝(针对=)

等号运算符重载函数,深拷贝要谨慎

stu& operator=(const stu& other){
    this->_name=other._name;
    this->_age=other._age;
    //判空,删除原空间,创建新空间
    if(this->_score!=nullptr){
    	delete []_score;
    } 
    this->_score=new int[10] ();
    memcpy(this->_score,other._score,10);
    cout << "stu equal operator overloading" <<endl;
    return *this;
}

测试代码:

#include <iostream>

using namespace std;

class stu{
    string _name;
    int _age;
    int *_score;
public:
    stu(string name,int age,int *score)
    {
        this->_name=name;
        this->_age=age;
        this->_score=new int[10] ();
        memcpy(this->_score,score,10);
//        this->_score=score;
        cout << "stu structure" << endl;
    }
    ~stu(){
        delete [] _score;
        cout << "stu destruct" << endl;
    }
    stu(const stu& other){
        this->_name=other._name;
        this->_age=other._age;
//        this->_p=other._p;
        //深拷贝
        this->_score=new int[10];
        memmove(this->_score,other._score,sizeof(int[10]));
        cout << "stu copy" <<endl;
    }
    //系统默认
    stu& operator=(const stu& other){
        this->_name=other._name;
        this->_age=other._age;
        //要必须小心
        if(this->_score!=nullptr){
            delete []_score;
        } 
        this->_score=new int[10] ();
        memcpy(this->_score,other._score,10);
        cout << "stu equal operator overloading" <<endl;
        return *this;
    }
    //自定义加法
    int operator+(const stu& other){
        return this->getAge()+other.getAge();
    }
    //自定义减法
    int operator-(const stu& other){
        cout << "class inside" << endl;
        return this->getAge()+other.getAge();
    }
    void showInfo()const{
        cout << "姓名: " << this->_name ;
        cout << "年龄: " << this->_age ;
        cout << "成绩: " << this->_score[0] ;
        cout << endl;
    }

    int getAge()const{
        return this->_age;
    }
};

const int operator-(const stu& s1,const stu& s2){
    cout << "class external" << endl;
    return s1.getAge()-s2.getAge();
}

const stu& compair(const stu& s1,const stu& s2){
    return s1.getAge()>s2.getAge()?s2:s1;
}

//stu compair(stu s1,stu s2){
//    return s1.getAge()>s2.getAge()?s2:s1;
//}

int main()
{
    int score[10]={100,80,40};
    //显示调用
    stu s1("yaoliang",18,score);
    stu s2(s1);
    s2.showInfo();
    //隐式调用
    stu s3("minmin",17,score);
    stu s4=s3;
    s4.showInfo();

    s3=s2;
    s3.operator=(s2);
    s3.showInfo();//系统自动创建了一个等号运算符重载
    cout << "---stu's age compair ,input small age imformation----" << endl;
    compair(s2,s4).showInfo();

    cout << "--using operator overloading (overall situation) ,stu age sub--" << endl;
    cout << s1-s4 << endl;
    cout << operator-(s1,s4) << endl;

    cout << "-----------using operator overloading ,stu age add------------" << endl;
    cout << s1+s4 << endl;

    return 0;
}

注意:

  • 在全局不可重载的运算符:=,->,[],()
  • 不能重载:.(.运算符),::(域运算符),.*(. *运算符),?:(三目运算符),(sizeof运算符),(#预处理运算符)

自增自减运算符

前自增

返回值 operator++()

后自增:

返回值 operator++(int)//亚元

#include <iostream>
#include <unistd.h>

using namespace std;

class Clock{
    int min;
    int sec;
public:
    Clock(int m,int s){
        this->min=m;
        this->sec=s;
    }

    Clock& operator++(){
        ++sec;
        if(0==sec%60){
            ++min;
            sec=0;
            if(0==min%60){
                this->min=0;
            }
        }
        return *this;
    }
    Clock& operator++(int){
        sec++;
        if(sec%60==0){
            min++;
            sec=0;
            if(min%60==0){
                this->min=0;
            }
        }
        return *this;
    }
    //Clock& operator++(int){
    //	  this->operator++();
    //    (*this).operator++();
    //    return ++*this;//三种效果一致
    //}
    
    void display(){
        cout << this->min << ":" << this->sec << endl;
    }
};

int main()
{
    Clock c(0,0);
    while(true){
        c++;
        c.display();
        sleep(1);
    }
    return 0;
}

封装一个字符串类

#include <iostream>
#include <string.h>
using namespace std;

class MyString{
private:
    char* m_data;
public:
    //MyString无参空构造
    MyString(){
        this->m_data=new char[1];
        this->m_data[0]='\0';
    }
    //MyString有参构造:在c++中字符串常量的类型,一定是const char* 类型
    MyString(const char* c_str){
        int len=strlen(c_str);
        this->m_data=new char[len+1];
        memmove(this->m_data,c_str,len);
        this->m_data[len]='\0';
    }
    //MyString 的拷贝构造
    MyString(const MyString& other){
        int len=strlen(other.m_data);
        this->m_data=new char[len+1];
        memmove(this->m_data,other.m_data,len);
        this->m_data[len]='\0';
    }
    //=号运算符重载函数
    MyString& operator=(const MyString& other){
        if(this==&other){
            return  *this;
        }
        int len=strlen(other.m_data);
        if(nullptr!=this->m_data){
            delete [] m_data;
            this->m_data=new char[len+1];
        }else{
            this->m_data=new char[len+1];
        }
        memmove(this->m_data,other.m_data,len);
        this->m_data[len]='\0';
        return  *this;
    }

    //析构
    ~MyString(){
        delete []m_data;
        this->m_data=nullptr;
    }

    //查找下标元素
    char operator[](int index){
        if(index < 0 || index >= strlen(this->m_data)){
            cout << "cross the border" << endl;
        }
        return  this->m_data[index];
    }
    //加法运算
    MyString operator+(const MyString& other){
        int my_len=strlen(this->m_data);
        int other_len=strlen(other.m_data);

        char *temp=new char[my_len+other_len+1];
        memmove(temp,this->m_data,my_len);
        memmove(temp+my_len,other.m_data,other_len);
        temp[my_len+other_len]='\0';

        MyString temp_str=temp;
        delete [] temp;
        return temp_str;
    }
    char* getM_data()const{
        return this->m_data;
    }
};
ostream& operator << (ostream& cout,const MyString& other){
    cout << other.getM_data();
    return cout;
}

int main()
{
    MyString str;
    MyString str1("hello");
    MyString str2=str1;
    MyString str3="yao";
    MyString str4="liang";
    cout << str1.getM_data() << endl;
    cout << str1 << endl;
    cout << str2 << endl;
    cout << str1[2] << endl;
    cout << str3+str4 << endl;

    return 0;
}

初始化列表

const修饰的常属性(只读属性)的初始化方式。

在C++中const修饰的对象,必要初始化

类中构造函数的特殊语法(高效率):

类中构造函数的初始化列表早于构造函数,在对象开辟空间时,解决const问题

初始化列表语法:在类中构造函数后+:类中的属性(外部参数)

遵循原则:顺序初始化(忽略static修饰的属性)

#include <iostream>

using namespace std;

class Score{
    int score;
public:
    Score(int score){
        cout << this->score << endl;
    }
};

class stu{
    string _name;
    int _age=128;
    int _salary;
    string *_friend;
    Score _s=Score(100);
public:
    stu(string name,int age):_name(name),_age(age),_salary(10000),_friend(new string[10]{"sunsun"}),_s(Score(100))
    {
        cout << "stu的有参构造" << endl;
    }
    ~stu(){
        delete []_friend;
        cout << "stu destruct" << endl;
    }
    void showInfo(){
        cout << "姓名:" << this->_name << "  年龄:" << this->_age ;
        cout << "工资:" << this->_salary << " 朋友1:" << this->_friend[0] ;
        cout  << endl;

    }
};

int main()
{
    stu s1("yaoliang",18);
    s1.showInfo();
    Score s(10);
    return 0;
}

this指针

在c中的体现:

#include <stdio.h>

typedef void (*Pfunc_t)();

typedef struct Stu
{
    char *name;
    int age;
    Pfunc_t f;
}stu;

void showInfo(stu *const this){
    printf("姓名:%s,年龄:%d\n",this->name,this->age);
}

int main(int argc, const char *argv[])
{
    /*your code*/
    stu s={"yaoliang",20,showInfo};

    s.f(&s);
   return 0;
}

C++中this指针

  • 就是本对象的起始地址(const修饰的常地址)
  • 是隐藏(非静态)在成员函数最左侧的一个常变量形参

两种用法:

  • 区分属性名与形参名
  • 解引用,返回本对象
#include <iostream>

using namespace std;

class Stu{
    string name;
    int age;
public:
    //1.当成员函数中形参变量与类属性变量重名时,使用this加以区分
    Stu(string name,int age){
        this->name=name;
        this->age=age;
//        name=name;//error
//        age=age;//error
    }
    void showInfo(){
        cout << "姓名: " << this->name << " , 年龄: " << this->age << endl;
//        cout << "姓名: " << name << " , 年龄: " << age << endl;//error
    }
    //2.返回本对象  *this
    Stu& setName(string name){
        this->name=name;
        return *this;
    }
};

int main()
{
    Stu stu("yaoliang",18);
    stu.showInfo();
    stu.setName("liang").showInfo();
    return 0;
}

常对象和常成员函数(方法)

常对象,const修饰的对象

特性:

  • 只读,不可修改

  • 不能调用普通成员函数(有修改权限),只能调用常函数

常函数,const修饰的函数

特性:

  • 不修改函数类中的属性,只读
#include <iostream>

using namespace std;

class rectangle{
    int wide;
    int length;
public:
//    rectangle(int wide,int length){
//        this->wide=wide;
//        this->length=length;
//    }
    void setwide(int wide){
        this->wide=wide;
    }
    void setlength(int length){
        this->length=length;
    }

    int getArea()const{
        return this->wide*this->length;
    }
};

//更安全
const rectangle& compair(const rectangle& r1,const rectangle& r2){
    return r1.getArea()>r2.getArea()?r1:r2;
}

//rectangle& compair( rectangle& r1,rectangle& r2){
//    r1.setwide(10);
//    r1.setlength(100000);
//    return r1.getArea()>r2.getArea()?r1:r2;
//}

int main()
{
    int wide=10;
    int length=20;
    rectangle *rect1=new rectangle();
    rect1->setwide(wide);
    rect1->setlength(length);
    cout << "rectangle's area1 = " << rect1->getArea() << endl;

    wide=20;
    length=30;
    rectangle rect2;
    rect2.setwide(wide);
    rect2.setlength(length);
    cout << "rectangle's area2 = " << rect2.getArea() << endl;

    cout << "---------------------------------------------------" << endl;
    cout << "较大的面积为:" << endl;
    cout << compair(*rect1,rect2).getArea() << endl;

    return 0;
}

静态属性和静态成员函数

特点:

  • 静态属性**资源共享**

  • 静态属性隐藏于类域之中,可以通过域名+::(域名访问符)直接访问

  • 静态成员函数访问不到类中属性,原因:最左侧没有常变量形参this

  • 静态成员函数可以访问静态属性,与静态属性类似,不依赖于某个对象调用

  • static修饰

    • 修饰属性时,修饰的是属性的存储形式,需要在类外全局.cpp文件中定义:例:stu::count=0;
    • 修饰函数时,修饰的是级别,隐藏在本类的类域中,为全类服务,可以域名::方式直接调用
#include <iostream>

using namespace std;

class stu{
    string _name;
    const int _age=128;
    int _salary;
    string *_friend;
    static int count;
public:
    stu(string name,int age):_name(name),_age(age),_salary(10000),_friend(new string[10]{"sunsun"})
    {
        count++;
        cout << "stu的有参构造" << endl;
    }
    ~stu(){
        delete []_friend;
        cout << "stu destruct" << endl;
    }
    void showInfo(){
        cout << "姓名:" << this->_name << "  年龄:" << this->_age ;
        cout << "工资:" << this->_salary << " 朋友1:" << this->_friend[0] ;
        cout  << endl;
    }
    static int get_count(){
        return count;
    }
};

//需要在全局定义的原因:
//静态变量在声明时就需要开辟空间,而在类中不会开辟空间
int stu::count = 0;

int main()
{
    stu s1("yaoliang",18);
    s1.showInfo();
    cout << "count = "  << stu::get_count() << endl;//1
    return 0;
}

单例设计模式

一个类,在外部只能生成一个实例,最大限度的减小资源占用

以下为**饿汉式**:

  • 优点:线程安全
  • 缺点:占用一块堆上的资源
#include <iostream>

using namespace std;
class singleton{
private:
    //1.把类中的构造设置为私有
    singleton(){
        cout << "singleton的构造" << endl;
    }
    static singleton* my_instance;
public:
    //2.提供一个公有接口函数返回本对象的指针
    //3.公有接口不想依赖类对象的调用,是不是应该把该接口升级为static静态成员函数
    static singleton* getInstance(){
        //4.在类私有属性中定义一个静态的私有成员对象类型的属性指针,并把公有接口中返回出去
        return my_instance;
    }
};

//5.在类外完成对类中静态属性指针的初始化
singleton* singleton::my_instance=new singleton();

int main()
{
    singleton* s1=singleton::getInstance();
    singleton* s2=singleton::getInstance();
    singleton* s3=singleton::getInstance();

    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    return 0;
}

以下为**懒汉式**:

  • 优点:不用不占用资源
  • 缺点:
    • 生成死递归,所以懒汉不提供析构,只能自己创建
    • 不在使用全部申请的空间,线程不安全,所以要加智能锁
#include <iostream>
#include <mutex>
using namespace std;

//设置全局锁
mutex mtx;

class singleton{
private:
    //1.把类中的构造设置为私有
    singleton(){
        cout << "singleton的构造" << endl;
    }
    static singleton* my_instance;
public:
    //2.提供一个公有借口函数返回本对象的指针
    //3.公有接口不想依赖类对象的调用,是不是应该把该接口升级为static静态成员函数
    static singleton* getInstance(){
        //4.在类私有属性中定义一个静态的私有成员对象类型的属性指针,并把公有接口中返回出去
        //c++11智能锁类型(可被析构):
        lock_guard<mutex> lock(mtx);//c++11线程安全的懒汉式单例
        if(nullptr==my_instance){
            my_instance =new singleton();
        }
        return my_instance;
    }
    //懒汉式析构
    void destroy(){
        if(nullptr!=my_instance){
            delete my_instance;
            my_instance=nullptr;
        }
    }
    
    //析构
//    ~singleton(){
        delete my_instance;//生成死递归,所以懒汉不提供析构
//    }
};

//5.在类外完成对类中静态属性指针的初始化
singleton* singleton::my_instance=nullptr;

int main()
{
    singleton* s1=singleton::getInstance();
    singleton* s2=singleton::getInstance();
    singleton* s3=singleton::getInstance();

    cout << s1 << endl;
    cout << s2 << endl;
    cout << s3 << endl;
    return 0;
}

注意:类中的静态属性当其初始化时,可以调用类中的私有属性和方法

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

编程远泊

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值