C++学习笔记(一)

文章目录

    • 类基本
      • 类成员函数
      • 类访问修饰符
      • 构造函数与析构函数
      • 拷贝构造函数
      • 友元函数
      • this
      • 静态成员
    • 继承

类基本

类成员函数

在c++中,类成员函数一般在类内进行定义,但是也可以通过类内声明,在外部利用

范围解析运算符::来定义(对于一些大型的类,类当中只做声明,这样对类的成员以及结构就会显得非常清晰)。

#include 
#include 

using namespace std;
class Student
{
    public:
        int age;
        char name[20];
        char* setName(char* Name)
        {
            strcpy(name,Name);
            return name;
        }
        char* getName(void)
        {
            return name;
        }
        int setAge(int Age);
        int getAge(void);
    
};

int Student::setAge(int Age)
{
    age=Age;
    return age;
}

int Student::getAge(void)
{
    return age;
}

int main(void)
{
    Student stu;
    stu.setName("liuxin");
    stu.setAge(22);
    cout << stu.getName()<<endl;
    cout << stu.getAge() <<endl;

}

类访问修饰符

C++的访问修饰符包含:public,protected,private,私密性逐次降低,对于成员变量和成员函数,默认的访问修饰符是private的。

public没什么好说的,关键就是protected和private。

protected:

保护变量在派生类当中是可以被访问的。一般储存父类与子类的共有属性。

#include 
#include 
using namespace std;
enum Sex
{
    female,
    male
};
//学生类
class Student
{
    protected:        
        int age_; //成员变量的命名规范是以_结尾
        string name_;
    public:
        string setName(string name)
        {
            name_ = name;
            return name_;
        }
        string getName(void)
        {
            return name_;
        }

        int setAge(int Age)
        {
            age_=Age;
            return age_;
        }

        int getAge(void)
        {
            return age_;
        }
    
};


//高中生类
class SeniorStudent:public Student
{
    protected:
        string stu_id_;  
    public:
        string setStuId(Sex sex)
        {
            stu_id_="2019"+to_string(age_)+to_string(sex);
            return stu_id_;
        }

        string getStuId(void)
        {
            return stu_id_;
        }
};

int main(void)
{
    SeniorStudent senior_stu;
    senior_stu.setAge(17);
    senior_stu.setName("liuxin");
    Sex sex=male;
    senior_stu.setStuId(sex);
    cout << senior_stu.getStuId() << endl;

    //不能访问protected变量
    //cout << senior_stu.stu_id_ <

}

private:

实际操作中,我们一般会在私有区域定义数据,在公有区域定义相关的函数,以便在类的外部也可以调用这些函数。

————————分割—————————

在继承方面,访问修饰符同样也对类的继承起限定作用,例如public继承,子类对父类的所有访问效果均按照父类本身的修饰符原则,比如父类的成员的修饰符为public,者对于子类也是public,如果是protected就是protected,private一样。但是如果protected继承,则原本的public受限于protected,对于子类,也只能以protected访问。

构造函数与析构函数

构造函数

类的构造函数是类的一种特殊的成员函数,它会在每次创建类的新对象时执行。

构造函数的名称与类的名称是完全相同的,并且不会返回任何类型,也不会返回 void。构造函数可用于为某些成员变量设置初始值。

注意:对于构造函数来说,访问修饰符也有非常大的作用:

  1. 通常我们使用public来进行修饰构造函数。

  2. protected的构造函数可用于只能在子类中创建父类对象,不能在外面创建父类对象的程序中(将子类的构造函数设置为public,将父类设置为protected)。

  3. private的构造函数只能在类的成员函数访问,这种一般用于单例模式,由一个静态的成员函数(可在不创建实例的情况下进行调用。)进行对象的创建,比如想数据库的编程,我们希望只创建一个实例,不希望多个实例对数据库进行访问。

    单例模式举例:

    #include 
    #include 
    
    
    using namespace std;
    
    enum Sex
    {
        female,
        male
    };
    //学生类
    class Student
    {
        protected:        
            int age_; //成员变量的命名规范是以_结尾
            string name_;
        public:
            string setName(string name)
            {
                name_ = name;
                return name_;
            }
            string getName(void)
            {
                return name_;
            }
    
            int setAge(int Age)
            {
                static int index;
                age_=Age;
                return index++;
            }
    
            int getAge(void)
            {
                return age_;
            }
        
    };
    
    enum Position{Monitor,TeamLeader};
    
    //干部类
    class Officer:public Student
    {
        protected:
            Position position_;
        
            Position setPosition(Position position)
            {
                position_=position;
                return position_;
            }
        public:
            Position getPosition()
            {
                return position_;
            }
    
            
    
    };
    
    //高中生类
    class SeniorStudent:public Student
    {
        protected:
            string stu_id_;  
        public:
            string setStuId(Sex sex)
            {
                stu_id_="2019"+to_string(age_)+to_string(sex);
                return stu_id_;
            }
    
            string getStuId(void)
            {
                return stu_id_;
            }
    };
    
    //高中班长类,构造函数是private,对象是静态的,单例模式
    class SeniorMonitor:public SeniorStudent,public Officer
    {
        private:
            SeniorMonitor();
        public:
            static SeniorMonitor& Instance()
            {
                static SeniorMonitor senior_monitor;//由于单例模式,那么只能创建一次用静态代替,同时静态类型才能以引用返回。
                return senior_monitor;
            } 
            
    };
    SeniorMonitor::SeniorMonitor(void)
    {
        Position pos = Monitor;
        setPosition(pos);
    }
    
    
    
    
    int main(void)
    {
        SeniorMonitor& senior_monitor = SeniorMonitor::Instance();
        cout << senior_monitor.Officer::setAge(17) << endl;
        cout << senior_monitor.SeniorStudent::setAge(17)<< endl;
    
        //不能访问protected变量
        //cout << senior_stu.stu_id_ <
    
    }
    

析构函数

类的析构函数是类的一种特殊的成员函数,它会在每次删除所创建的对象时执行。

析构函数的名称与类的名称是完全相同的,只是在前面加了个波浪号(~)作为前缀,它不会返回任何值,也不能带有任何参数。析构函数有助于在跳出程序(比如关闭文件、释放内存等)前释放资源。如果没有手动删除对象,那么就会在作用域结束的时候进行调用。

—————————————割—————————————————————————

注意:派生类会自动调用基类的构造函数和析构函数,调用顺序是:基类带参构造函数,派生类带参构造函数,派生类析构,基类析构。另外,对于new出来的对象,必须要手动调用析构函数,因为new出来的对象都是在堆上开辟了一块内存,直到程序结束,堆上的内存都不会被清空。

拷贝构造函数

拷贝构造函数是一种特殊的构造函数,它在创建对象时,是使用同一类中之前创建的对象来初始化新创建的对象。拷贝构造函数通常用于:

  • 通过使用另一个同类型的对象来初始化新创建的对象。
  • 复制对象把它作为参数传递给函数。(这种传递方式,为值传递方式,除非有动态资源,否则不会影响原对象)
  • 复制对象,并从函数返回这个对象。

如果在类中没有定义拷贝构造函数,编译器会自行定义一个。如果类带有指针变量,并有动态内存分配,则它必须有一个拷贝构造函数。拷贝构造函数的最常见形式如下:

classname (const classname &obj) {
    // 构造函数的主体 
}

最普通的情况就是利用一个已经初始化好的对象,去初始化另一个相同类型的对象,如果没有自己定义,工作流程如下所示。


//小组长类,有多个小组长,就不要用单例模式了
class SeniorTeamLeader:public SeniorStudent,public Officer
{
    private:
        int team_id_;
    public:
        SeniorTeamLeader(int team_id); 
        SeniorTeamLeader(const SeniorTeamLeader& obj);
};
SeniorTeamLeader::SeniorTeamLeader(int team_id)
{
    //构造函数
    Position pos = TeamLeader;
    setPosition(pos);
    team_id_=team_id;
}
SeniorTeamLeader::SeniorTeamLeader(const SeniorTeamLeader& obj)
{
    //构造复制函数
    team_id_=obj.team_id_;
    cout << "复制构造函数被调用" << endl;
}


void test()
{
    SeniorStudent* senior_student =new SeniorStudent();
    (*senior_student).getStuId();
    

}


int main(void)
{
    test();
    SeniorMonitor& senior_monitor = SeniorMonitor::Instance();
    SeniorTeamLeader seninor_team_leader1(1);  //这里初始化了一个对象
    SeniorTeamLeader seninor_team_leader2 = seninor_team_leader1;//利用初始化后的对象初始化另一个对象。

    //不能访问protected变量
    //cout << senior_stu.stu_id_ <

}

注意:在某些状况下,类内成员变量需要动态开辟堆内存,如果实行位拷贝,也就是把对象里的值完全复制给另一个对象,如A=B。这时,如果B中有一个成员变量指针已经申请了内存,那A中的那个成员变量也指向同一块内存。这就出现了问题:当B把内存释放了(如:析构),这时A内的指针就是野指针了,出现运行错误。深拷贝和浅拷贝可以简单理解为:如果一个类拥有资源,当这个类的对象发生复制过程的时候,资源重新分配,这个过程就是深拷贝,反之,没有重新分配资源,就是浅拷贝。下面举个深拷贝的例子。

这种情况下就一定需要自己去定义拷贝函数,手动开辟空间,重新分配资源,由于初学,我这里不再做一个更为详细的记录,等到后面在进行更新。

友元函数

类的友元函数是定义在类外部,但有权访问类的所有私有(private)成员和保护(protected)成员。尽管友元函数的原型有在类的定义中出现过,但是友元函数并不是成员函数。

友元可以是一个函数,该函数被称为友元函数;友元也可以是一个类,该类被称为友元类,在这种情况下,整个类及其所有成员都是友元。

如果要声明函数为一个类的友元,需要在类定义中该函数原型前使用关键字 friend,如下所示:

//小组长类,有多个小组长,就不要用单例模式了
class SeniorTeamLeader:public SeniorStudent,public Officer
{
    private:
        int team_id_;
    public:
        SeniorTeamLeader(int team_id); 
        SeniorTeamLeader(const SeniorTeamLeader& obj);

        int setTeamId(int team_id);
        int getTeamId(void);
        
        //友元函数
        friend void test(SeniorTeamLeader obj);
};
SeniorTeamLeader::SeniorTeamLeader(int team_id)
{
    //构造函数
    Position pos = TeamLeader;
    setPosition(pos);
    team_id_=team_id;
}
SeniorTeamLeader::SeniorTeamLeader(const SeniorTeamLeader& obj)
{
    //构造复制函数
    team_id_=obj.team_id_;
    cout << "复制构造函数被调用" << endl;
}
int SeniorTeamLeader::setTeamId(int team_id)
{
    team_id_=team_id;
}
int SeniorTeamLeader::getTeamId(void)
{
    return team_id_;
}

void test(SeniorTeamLeader obj)
{
    cout << obj.team_id_ << endl;
}


int main(void)
{
    SeniorMonitor& senior_monitor = SeniorMonitor::Instance();
    SeniorTeamLeader senior_team_leader1(1);
    SeniorTeamLeader senior_team_leader2 = senior_team_leader1;

    senior_team_leader2.setTeamId(2);
    test(senior_team_leader2);
    cout << senior_team_leader1.getTeamId() << endl;


    //不能访问protected变量
    //cout << senior_stu.stu_id_ <

}

this

this指针跟python类似,都是指向对象自己的指针,但C++中不需要显示的表现出来。

this指针的使用:
一种情况就是,在类的非静态成员函数中返回类对象本身的时候,直接使用 return *this;另外一种情况是当参数与成员变量名相同时,如this->n = n (不能写成n = n)。

静态成员

静态成员变量

我们可以使用 static 关键字来把类成员定义为静态的。当我们声明类的成员为静态时,这意味着无论创建多少个类的对象,静态成员都只有一个副本。

静态成员在类的所有对象中是共享的。如果不存在其他的初始化语句,在创建第一个对象时,所有的静态数据都会被初始化为零。我们不能把静态成员的初始化放置在类的定义中,但是可以在类的外部通过使用范围解析运算符 :: 来重新声明静态变量从而对它进行初始化。

静态成员函数

如果把函数成员声明为静态的,就可以把函数与类的任何特定对象独立开来。静态成员函数即使在类对象不存在的情况下也能被调用,静态函数只要使用类名加范围解析运算符 :: 就可以访问。

注意:静态成员函数只能访问静态成员数据、其他静态成员函数和类外部的其他函数。

静态成员函数有一个类范围,他们不能访问类的 this 指针。您可以使用静态成员函数来判断类的某些对象是否已被创建。

静态成员函数与普通成员函数的区别:

  • 静态成员函数没有 this 指针,只能访问静态成员(包括静态成员变量和静态成员函数)。
  • 普通成员函数有 this 指针,可以访问类中的任意成员;而静态成员函数没有 this 指针。

我们可以利用静态成员来进行记录某个类的实例化次数。

比如,记录小组长对象有多少个:


//小组长类,有多个小组长,就不要用单例模式了
class SeniorTeamLeader:public SeniorStudent,public Officer
{
    private:
        int team_id_;
    public:
        static int objectCount;

        SeniorTeamLeader(int team_id); 
        SeniorTeamLeader(const SeniorTeamLeader& obj);

        int setTeamId(int team_id);
        int getTeamId(void);
        
        //友元函数
        friend void test(SeniorTeamLeader obj);
        static int getCount()
        {
            return objectCount;
        }
};
//只能在
int SeniorTeamLeader::objectCount=0;
SeniorTeamLeader::SeniorTeamLeader(int team_id)
{
    //构造函数
    Position pos = TeamLeader;
    setPosition(pos);
    team_id_=team_id;
    objectCount++;
    cout << "构造函数" << endl;
}
SeniorTeamLeader::SeniorTeamLeader(const SeniorTeamLeader& obj)
{
    //构造复制函数
    team_id_=obj.team_id_;
    objectCount++;
    cout << "复制构造函数被调用" << endl;
}
int SeniorTeamLeader::setTeamId(int team_id)
{
    team_id_=team_id;
}
int SeniorTeamLeader::getTeamId(void)
{
    return team_id_;
}


void test(SeniorTeamLeader obj)
{
    cout << obj.team_id_ << endl;
}


int main(void)
{
    SeniorMonitor& senior_monitor = SeniorMonitor::Instance();
    SeniorTeamLeader senior_team_leader1(1);


    cout <<"被调用"<< SeniorTeamLeader::getCount() <<"次"<< endl;


    //不能访问protected变量
    //cout << senior_stu.stu_id_ <<endl;

}

继承

一个派生类继承了所有的基类方法,但下列情况除外:

  • 基类的构造函数、析构函数和拷贝构造函数。
  • 基类的重载运算符。
  • 基类的友元函数。

多继承

继承多个类。

附加要点:

string,char[],char*,const char*区别

C++引用

你可能感兴趣的:(C/C++)