C++基础知识三

一、构造函数的参数初始化列表
注意:1.初始化参数列表优先于当前对象的构造函数执行
2.子对象的初始化顺序和在其初始化列表的排序无关,但是和在类中的声明顺序有关,先声明的先初始化

#include <iostream>

using namespace std;

class Date
{
    
    
    private:
        int m_year;
        int m_month;
        int m_day;
    public:
        Date(int y, int m, int d)
        {
    
    
            cout<<"Date的有参构造"<<endl;
            m_year = y;
            m_month = m;
            m_day = d;
        }
};
//对象的初始化列表:1.类对象作为另一个类的成员变量时,类对象没有提供默认的无参构造函数,2.成员变量使用const修饰

class Student
{
    
    
    private:
        const int id;
        Date birth;

    public:
        Student(int i, int y, int m, int d):birth(y,m,d),id(i)  //对象初始化列表
        {
    
    
            cout<<"student的有参构造函数"<<endl;
        }
};

int main(int argc, char * argv[])
{
    
    
    Student s1(001, 1997,1,1);

    return 0;
}

二、静态成员变量和静态成员函数
(1) 静态成员变量
1)在C++中,我们可以使用静态成员变量来实现多个对象共享数据的目标,静态成员变量是一种特殊的成员变量,有关键词static修 饰

#include <iostream>
using namespace std;

class Student
{
    
    
    public:
        static int count;     //静态成员变量,所有对象共享同一个静态成员变量
    
    private:
        int id;

    public:
        Student()
        {
    
    
            count++;
            id = count;
        }

        static int GetCount()   //静态成员函数
        {
    
    
            //id++;   //静态成员函数只能调用静态成员变量
            return count;
        }

        int GetCount1()
        {
    
    
            return count;   //普通函数可以访问静态成员变量
        }
};

int Student::count = 0;   // 静态成员变量一定要在类的外部初始化

int main(int argc, char *argv[])
{
    
    
    Student s1;
    Student s2;

    cout<<s1.count<<endl;
    cout<<s2.count<<endl;
    cout<<Student::count<<endl;       //静态成员变量可以直接通过类名来访问
    cout<<Student::GetCount()<<endl;  //静态成员函数可以直接通过类名来访问
    cout<<s1.GetCount1()<<endl;  

    return 0;
}

三、友元
3.1 友元函数

#include <iostream>
using namespace std;

class Test
{
    
    
    friend void Show(Test &t);   //友元函数
    private:
        int m_a;
    
    public:
        Test()
        {
    
    
            m_a = 100;
        }

        void show()
        {
    
    
            cout<<"m_a = "<<m_a<<endl;
        }
};

void Show(Test &t)
{
    
    
    cout<<"m_a = "<<t.m_a<<endl;
}

int main(int argc, char * argv[])
{
    
    
    Test t1;
    t1.show();

    Show(t1);
    return 0;

    return 0;
}
3.2 友元类
#include <iostream>
using namespace std;

class Test2;
class Test
{
    
    
    friend class Test2;   //友元类,可以在类Test2中访问Test的私有成员

    private:
        int m_a;
    
    public:
        Test()
        {
    
    
            m_a = 100;
        }

        void show()
        {
    
    
            cout<<"m_a = "<<m_a<<endl;
        }
};

class Test2
{
    
    
    friend class Test;   //友元类
    
    private:
        int m_b;
    
    public:
        Test2()
        {
    
    
            m_b = 200;
        }

        void print(Test &t)    //友谊是单向的
        {
    
    
            cout<<"m_a = "<<t.m_a<<endl;
        }
};


int main(int argc, char *argv[])
{
    
    
    Test t1;
    Test2 t2;
    t2.print(t1);

    return 0;
}

四、继承和派生
4.1 继承的概念和语法
继承可以理解为一个类从另一个类获取成员变量和成员函数的过程
例如:类B继承于类A,那么B就用有A中的成员变量和成员函数。被继承的类称为父类或者基类,继承的类称为子类或者派生类。

4.2 继承的语法

#include <iostream>
#include <cstring>

using namespace std;

class Person    //父类或者基类
{
    
    
    protected:
        char m_name[32];
        int m_age;
    
    public:
        Person()
        {
    
    
            strcpy(m_name,"小苗");
            m_age = 18;
        }
};

class Student:public Person     //子类或者派生类,public继承权限
{
    
    
    private:
        int id;
    
    public:
        Student(int id)
        {
    
    
            this->id;
        }

        void show()
        {
    
    
            cout<<"m_name = "<<m_name<<" m_age = "<<m_age<<" id = "<<id<<endl;
        }
};

int main(int argc, char *argv[])
{
    
    
    Student s1(100);
    s1.show();
    
    return 0;
}

在这里插入图片描述
4.3 继承的权限
(1)共有继承(public)
1.基类的public在派生类中具有public属性,派生类的内部和外部都可以访问
2.基类的protected在派生类中有protected属性,派生类的内部可以访问,外部不可以访问
3.基类中的private在派生类中不可以访问。
(2)保护继承(protected)
1.基类的public在派生类中具有protected属性,派生类的内部可以访问,外部不可以访问
2.基类的protected在派生类中有protected属性,派生类的内部可以访问,外部不可以访问
3.基类中的private在派生类中不可以访问。
(3)私有继承(private)
1.基类的public在派生类中具有private属性,派生类的内部可以访问,外部不可以访问
2.基类的protected在派生类中有private属性,派生类的内部可以访问,外部不可以访问
3.基类中的private在派生类中不可以访问。

#include <iostream>

using namespace std;

class TestA   //父类或者基类
{
    
    
    private:
        int m_a;
    
    protected:
        int m_b;

    private:
        int m_c;
};

class TestB:private TestA   //子类继承
{
    
    
    
    private:
        int m_a;   //不可继承

    private:
        int m_b;   //在派生类中私有,只能在类中访问
    
    private:
        int m_c;  //在派生类中私有,只能在类中访问
    
    public:
        void show()
        {
    
    
            m_a++;  //在TestA中,m_a是私有成员变量,不能访问
            m_b++;
            m_c++;
        }

};

class TestC:protected TestA   //子类继承
{
    
    
    private:
        int m_a;

    protected:
        int m_b;    //在派生类中为保护属性,可以在本类和继承的类中访问
    
    private:     //在派生类中为保护属性,可以在本类和继承的类中访问
        int m_c;
    
    public:
        void show()
        {
    
    
            m_a++;  //在TestA中,m_a是私有成员变量,不能访问
            m_b++;
            m_c++;
        }

};

class TestD:public TestA   //子类继承
{
    
    
    
    private:
        int m_a;   //不可继承

    protected:    //在派生类中为保护属性,可以在本类和继承的类中访问
        int m_b;
    
    public:
        int m_c;  //在派生类中为公有属性,可以在类的内部和外部访问
    
    public:
        void show()
        {
    
    
            m_a++;  //在TestA中,m_a是私有成员变量,不能访问
            m_b++;
            m_c++;
        }

};

int main(int argc, char *argv[])
{
    
    
    TestB t1;
    t1.show();

    TestC t2;
    t2.show();

    TestD t3;
    t3.show();

    return 0;
}

4.4 继承的模型

在这里插入图片描述

#include <iostream>

using namespace std;

class Person   //父类
{
    
    
    public:
        int m_age;
};

class Student:public Person   //子类或者派生类
{
    
    
    public:
        int m_id;
};

int main(int argc, char const *argv[])
{
    
    
    Student s1;
    cout<<sizeof(s1)<<endl;
    cout<<&s1<<endl;
    cout<<&s1.m_age<<endl;
    cout<<&s1.m_id<<endl;

    return 0;
}

在这里插入图片描述
4.5 继承的构造
类的构造函数不能被继承,因为即使继承了基类的构造函数,名字也和派生类不一样。
构造顺序:
先构造基类,在构造类成员对象,最后构造自己,构造顺序和形参初始化列表无关。
类的构造函数和析构函数不能被继承

#include <iostream>
#include <cstring>
using namespace std;

class Person
{
    
    
    protected:
        char m_name[32];
        int m_age;

    public:
        Person(const char *name, int age)
        {
    
    
            cout<<"person的构造函数"<<endl;
            strcpy(this->m_name, name);
            m_age = age;
        }

        ~Person()
        {
    
    
             cout<<"person的析构函数"<<endl;
        }
};

class Date
{
    
    
    private:
        int m_year;
        int m_month;
        int m_day;
    public:
        Date(int y, int m, int d)
        {
    
    
            cout<<"Date的有参构造"<<endl;
            m_year = y;
            m_month = m;
            m_day = d;
        }
        ~Date()
        {
    
    
             cout<<"Date的析构函数"<<endl;
        }
};

class Student:public Person
{
    
    
    private:
        int m_id;
        Date birth;
    
    public:
        Student(int id):birth(1996,1,1),Person("xiaoming",25)
        {
    
    
            cout<<"student的构造函数"<<endl;
            m_id = id;
        }

        void show()
        {
    
    
            cout<<"  m_name = "<<m_name<<"  m_age = "<<m_age<<"  m_id = "<<m_id<<endl;
        }

        ~Student()
        {
    
    
             cout<<"Student的析构函数"<<endl;
        }
};

int main(int argc, char const *argv[])
{
    
    
    Student s1(100);
    s1.show();

    return 0;
}

4.6 const修饰成员函数
1)const修饰成员函数
1.成员函数后加const称这个函数为常函数;
2.常函数不可以修改成员变量;
3.成员变量前加mutable后,即可在常函数中修改。
2)常对象
1.声明对象前加const的对象称为常对象;
2.常对象只能调用常函数。

#include <iostream>
using namespace std;

class Student
{
    
    
    private:
        int m_id;
        char *m_name;
        int m_age;
    
    public:
        Student(int id, char *name, int age);
        void show();
        char *GetName() const;
        int GetId() const;
        int GetAge() const;
};

void Student::show()
{
    
    
    cout<<"m_name = "<<m_name<<" m_age = "<<m_age<<" m_id = "<<m_id<<endl;
}

char* Student::GetName() const   //成员函数必须在声明和定义处都加上const关键词
{
    
    
    return m_name;
}  

int Student::GetId() const   //成员函数必须在声明和定义处都加上const关键词
{
    
    
    return m_id;
}

int Student::GetAge() const   //成员函数必须在声明和定义处都加上const关键词
{
    
    
    return m_age;
}

Student::Student(int id, char* name, int age):m_id(id),m_name(name),m_age(age)
{
    
    

}

int main(int argc, char const *argv[])
{
    
    
    Student s1(100, "Xiaoming", 19);
    s1.show();
    return 0;
}

4.7 同名成员

#include <iostream>
using namespace std;

class TestA
{
    
    
    private:
        int m_a;
    
    public:
        void show()
        {
    
    
            cout<<"this is TestA"<<endl;
        }
};

class TestB:public TestA
{
    
    
    private:
        int m_a;
    
    public:
        void show()
        {
    
    
            cout<<"this is TestB"<<endl;
        }
};

int main(int argc, char const *argv[])
{
    
    
    TestB tb;
    cout<<sizeof(tb)<<endl;

    tb.show();   //同名,默认调用派生类中的成员函数,基类成员被隐藏
    tb.TestA::show();   //显示调用

    return 0;
}

4.8 继承中的static关键词
如果在基类中定义了静态成员变量,则静态成员变量将被所有多有的派生类共享

#include <iostream>
using namespace std;

class Person
{
    
    
    public:
        static int count;
    
    Person()
    {
    
    
        this->count++;
    }
};

int Person::count = 0;

class Student:public Person
{
    
    

};

int main(int argc, char const *argv[])
{
    
    
    Student s1;
    Student s2;
    Person p1;
    Person p2;
    //Person p3;

    cout<<Person::count<<endl;    //派生类和基类共享一个静态成员变量
    cout<<Student::count<<endl;

    return 0;
}

4.9 继承中的类型兼容性原则
在这里插入图片描述

#include <iostream>
#include <cstring>

using namespace std;

class Person
{
    
    
    protected:
        char m_name[32];
        int m_age;

    public:
        Person()
        {
    
    
            cout<<"Person的无参构造函数"<<endl;
            strcpy(m_name,"LDD");
            m_age = 18;
        }

        void SetValue(char *name, int age)
        {
    
    
            strcpy(m_name,name);
            m_age = age;
        }

        Person(const Person &p)
        {
    
    
            cout<<"Parent的拷贝构造"<<endl;
            strcpy(m_name,p.m_name);
            m_age = p.m_age;
        }

        void print()
        {
    
    
            cout<<"m_name = "<<m_name<<" m_age = "<<m_age<<endl;
        }
};

class Student:public Person
{
    
    
    private:
        int id;
    public:
        void SetId(int i)
        {
    
    
            id = i;
        }

        void show()
        {
    
    
            cout<<"m_name = "<<m_name<<" m_age = "<<m_age<<" id = "<<id<<endl;
        }
};

int main(int argc, char const *argv[])
{
    
    
    Person p1;
    p1.SetValue("zhangsan",18);
    p1.print();

    Student s1;
    s1.SetValue("lisi",20);
    s1.SetId(200);
    
    Student *ps = &s1;  
    ps->show();

    Person *p = &s1;         //基类指针可以直接指向派生类对象   子类指针不能指向派生类对象
    p->SetValue("wnger",30);
    p->print();


    Person &p2 = s1;    //基类引用可以直接指向派生类对象
    p2.print();

    Person p3 = s1;    //子类对象可以直接初始化基类对象
    p3.print();


    return 0;
}

4.10 多继承
1.多继承概念
1)派生类中只有一个基类,被称为单继承,除此之外,C++也支持多继承,即一个派生类可以有多个基类
2)多继承容易让代码逻辑复杂,思维混乱,一直备受争议,在中小型项目中,很少使用。
2.多继承的语法

#include <iostream>

using namespace std;

class BaseA
{
    
    
    protected:
        int m_a;
        int m_b;
    public:
        BaseA(int a, int b);
        ~BaseA();
};

BaseA::BaseA(int a, int b):m_a(a),m_b(b)
{
    
    
    cout<<"BaseA构造函数被调用"<<endl;
}

BaseA::~BaseA()
{
    
    
    cout<<"BaseA析构函数被调用"<<endl;
}

class BaseB
{
    
    
    protected:
        int m_c;
        int m_d;
    public:
        BaseB(int c, int d);
        ~BaseB();
};

BaseB::BaseB(int c, int d):m_c(c),m_d(d)
{
    
    
    cout<<"BaseB构造函数被调用"<<endl;
}

BaseB::~BaseB()
{
    
    
    cout<<"BaseB析构函数被调用"<<endl;
}

class Deived:public BaseA,public BaseB
{
    
    
    private:
        int m_e;
    public:
        Deived(int a, int b, int c, int d, int e);
        ~Deived();
        void show()
        {
    
    
            cout<<m_a<<" , "<<m_b<<" , "<< m_c<<" , "<<m_d<<" , "<<m_e<<endl;
        }
};

Deived::Deived(int a, int b, int c, int d, int e):BaseA(a,b),BaseB(c,d),m_e(e)
{
    
    
    cout<<"deived的构造函数"<<endl;
}

Deived::~Deived()
{
    
    
    cout<<"deived的析构函数"<<endl;
}

int main(int argc, char const *argv[])
{
    
    
    Deived d(1,2,3,4,5);
    d.show();
    return 0;
}

在这里插入图片描述

	3.多继承的二义性

在这里插入图片描述

#include <iostream>
using namespace std;

class BaseA
{
    
    
    protected:
        int m_a;
        
};

BaseA::BaseA()
{
    
    
    cout<<"BaseA构造函数被调用"<<endl;
}

BaseA::~BaseA()
{
    
    
    cout<<"BaseA析构函数被调用"<<endl;
}

class BaseB:public BaseA
{
    
    
    protected:
        int m_b;
        int m_c;
        int m_d;

};

BaseB::BaseB()
{
    
    
    cout<<"BaseB构造函数被调用"<<endl;
}

BaseB::~BaseB()
{
    
    
    cout<<"BaseB析构函数被调用"<<endl;
}


class BaseC:public BaseA
{
    
    
    protected:
        int m_c;
        
};

BaseC::BaseC()
{
    
    
    cout<<"BaseA构造函数被调用"<<endl;
}

BaseC::~BaseC()
{
    
    
    cout<<"BaseA析构函数被调用"<<endl;
}


class BaseD:public BaseB,public BaseC
{
    
    
    protected:
        int m_d;
        
};

BaseD::BaseD()
{
    
    
    cout<<"BaseA构造函数被调用"<<endl;
}

BaseD::~BaseD()
{
    
    
    cout<<"BaseA析构函数被调用"<<endl;
}


int main(int argc, char const *argv[])
{
    
    
    BaseD td;
    cout<<sizeof(td)<<endl;
    td.m_a;  //报错

    return 0;
}

5.虚继承

在这里插入图片描述

#include <iostream>
using namespace std;

class BaseA
{
    
    
    protected:
        int m_a;
        
};

class BaseB:virtual public BaseA
{
    
    
    protected:
        int m_b;
      
};

class BaseC:virtual public BaseA
{
    
    
    protected:
        int m_c;
        
};

class BaseD:public BaseB,public BaseC
{
    
    
    protected:
        int m_d;
        
};




int main(int argc, char const *argv[])
{
    
    
    BaseB tb;
    cout<<sizeof(tb)<<endl;
    cout<<&tb<<endl;
    cout<<&tb.m_a<<endl;  //报错
    cout<<&tb.m_b<<endl;  //报错

    cout<<"************************"<<endl;

    BaseD td;
    cout<<sizeof(td)<<endl;
    cout<<&td<<endl;
    cout<<&td.m_a<<endl;  //报错
    cout<<&td.m_b<<endl;  //报错
    cout<<&td.m_c<<endl;  //报错
    cout<<&td.m_d<<endl;  //报错


    return 0;
}

6.向上转型

#include <iostream>
using namespace std;

class Parent
{
    
    
    private:
        int m_a;
};

class Child:public Parent
{
    
    
    private:
        int m_b;
};

int main(int argc, char const *argv[])
{
    
    
    int a = 11.7;
    double b = 2;

    Parent p;
    Child c;
    p = c;   //只能将派生类对象赋值给基类对象,派生类引用,指针赋值给基类引用, 指针->向上转型

    //c = p;

    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43296982/article/details/123844069