C++基础

一.命名空间,关键字升级,C++对C的加强(引用),C++对C的函数扩展

(一)命名空间
1、定义:namespace 名字{变量、函数}
使用方法
(1)使用作用域限定符:命名空间的名字::变量名或者函数名
(2)使用using关键字导入明明空间:using 命名空间(可能多个命名空间含有相同变量名产生二义性) 或者 using 命名空间::变量名或者函数名
::作用域限定符
2、using namespace std:标准库命名空间
作用:C++为了防止和C冲突,将新的一些函数定义在标准库中。
使用注意事项
(1)源文件不能访问其他源文件的命名空间
(2)当多个源文件的命名空间名字相同时:
如果两个命名空间函数名或者变量名没有出现重复,就会合并,可理解为追加
如果两个命名空间有相同的函数名或者变量名,就会报错

#include <iostream>
//filename:add.cpp
//static int count = 5;  //c语言解决命名冲突的方法

namespace A
{
    int count =5;

    void print()
    {
        std::cout << "hello world" <<std:: endl ;
    }
}
namespace C
{
    int count = 6;
}

//using namespace A
//using A::print

int add(int a,int b)
{
    return a-b-A::count;
}


#include <iostream>

extern int add(int a,int b);

//using namespace std //标准库命名空间

int main()
{
    std::cout<<add(0,0)<<std::endl;

    return 0;
}

(二)输入输出
1、对象:
(1)cin:输入流
(2)cout:输出流
(3)cerr:错误流
(4)clog:日志流 有缓冲
2、流运算符:
(1)>>:输入
(2)<<:输出
3、注意事项:
(1)printf:有行缓冲(满一行或者遇到"\n"输出)
使用printf调试时,一定要加"\n"或者手动刷新缓冲区
(2)scanf:输入前,刷新缓冲区
(3)cout:也有行缓冲,加上endl

#include <iostream>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdio.h>

using namespace std;

int main()
{
    /*
    int fd = open("a.txt",O_RDWR | O_CREAT,0655);
    if(fd==-1)
    {
        cerr<<"error"<<endl;
    }

    cerr<<"hello" ;
    while(1);

    printf("hello");
    while(1);
    */

    int num;
    char ch;
    char src[100];
    
    cin>>num;
    //解决行冲突
    //getchar();//c语言接收换行符
    cin.get(); //c++接收换行符
    cin>>ch;
    cin.get();
    //cin>>src;
    cin.getline(src,100); //接收一行100个字符的内容

    cout<<"num="<<num<<endl;
    cout<<"ch="<<ch<<endl;
    cout<<"src="<<src<<endl;


    return 0;
}

(三)C++对C的实用性加强
1、基本语句的升级
(1)for语句:优化了循环变量的作用域
(2)条件表达式:可以做左值

2、关键字的升级
(1)register关键字的升级:若对一个register变量取地址,会将该变量重新保存到内存中。
C语言中:尽可能的将该变量保存到cpu内部寄存器中,从而省去从内存中抓取数据的时间,提高程序运行的效率;
C语言中register使用注意事项:
只能修饰局部,不能修饰全局变量和函数
C语言中register修饰变量,不能通过&获取该变量的地址
register修饰的变量类型,必须是时cpu所能够接受的类型
(2)const关键字的升级:const修饰的变量是常量
C语言中const修饰的变量是只读变量
地址之间的赋值必须是const对const
(3)auto关键字:类型推导,实现高效编程
example:
string::interator it = s1.begin();
aoto inter2 = s1.begin();
这样两个类型就一致了
C语言中auto关键字:自动变量,只是用来说明该变量的作用域;相当于局部变量
(4)using关键字的升级:替代C语言中的typedef的关键字
typedef关键字的作用:给类型重命名;提高代码的可读性、移植性;

3、类型的升级
(1)引入了bool类型 占一个字节
(2)引入了”引用“
1、定义:给变量起别名,定义引用必须初始化,一旦绑定就不能再次绑定到其他变量上。
2、作用:解决了函数传值和传地址的问题。
3、应用场景:作为函数的形参,作为函数的返回值(函数调用可以用作左值)
4、常引用:const修饰的引用,绑定常量
5、引用的分类
左值引用(&):只能绑定在左值;右值引用(&&):只能绑定在右值
左值:可以取地址,可以修改
右值:不可以取地址,不可以修改
右值引用的目的:实现对象移动,解决临时对象拷贝开销问题;
std::move():将左值转化成右值
6、引用是不是数据类型?占不占用内存空间?
引用不是数据类型,运行时不占用内存空间,编译时预留内存空间!!!!

引用不是一种独立的数据类型,对引用只有声明没有定义
7、指针和引用的区别?
指针指向一块内存,它的内容是所指内存的地址;引用是某块内存的别名。
指针:指针是一个变量,只不过这个变量存储的是一个地址,指向内存的一个存储单元,即指针是一个实体;而引用跟原来的变量实质上是一个东西,只不过是原变量的一个别名而已。
8、什么是对象移动?作用是什么?
对象移动:本身并不移动对象,只是将对象的类型转换为右值。
对象移动的作用:实现移动构造函数和移动赋值运算符
C语言中传地址,才可以改变两个实参的值。
(3)用new、delete运算符来替代malloc、free
1、malloc 按照字节为单位,new按照数据类型的个人为单位
2、malloc不能初始化内存,new可以初始化
3、malloc是函数,new是运算符
(四)C++对C的升级
1、函数的升级
(1)引入inline关键字修饰函数:用(内存)空间换运行时间(减少函数的调用和返回)
限制:
内联函数不可含有循环
内联函数不可含有静态变量
内联函数不可为递归函数
内联函数不可含有错误处理
注意事项:
一般内联函数必须在第一次调用之前
(2)引用了默认参数:可以给形参设定默认参数(规则:默认参数右边的参数必须全为默认参数)
(3)可以使用函数的重载:可以使用相同函数名,重载规则:形参的个数、类型或者顺序不同。
初始int add(int a,int b)
重载1:int add(int a,int b,int c)
重载2:int add(char a,char b)
重载3:int add(int b,int a)
注意事项:
函数返回值不能作为重载条件;默认参数值会影响重载。
(4)引入了参数占位符
int add(int a,string b,int)
最后一个int为参数占位符,提示以后可能会升级.

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

int add(int a, int b)
{
    return a + b;
}

int sup(int a,int b=1)//默认参数
{
    return a-b;
}

//函数的重载
int add(int a,int b,int c)
{}
int add(double a,char b)
{}


void swap(int &left, int &right)
{
    int temp;
    temp = left;
    left = right;
    right = temp;
}

int & test()
{
    static int num = 5;
    cout << num << endl;
    return num;
}

int func(const int &num1, const int &num2)
{

}

int main()
{
#if 0
    //C++对C的升级:基本语句的升级
    //for语句:优化循环变量的作用域

    for (int i = 0; i < 100; i++)
    {
    }

    //条件表达式:可以做左值
    int a = 5;
    int b = 6;

    int max = a > b ? a : b;
    (a > b ? a : b) = 69;  //只修改b的值
    cout << b << endl;

    //C++对C的升级:关键字的升级
    //register关键字的升级:若对register变量取地址,会将该变量重新保存到内存中;
    //C语言: //2\register修饰变量,不能通过&获取该变量的地址;
    
    register int count = 6;
    int *p = &count;

    //const关键字的升级:const修饰是常量;
    //地址之间的赋值必须是const对const;

    const int num = 5;
    const int *p_num = &num;
    //*p_num = 7;

    //auto关键字
    //C语言auto关键字:自动变量,只是用来说明该变量的作用域;相当于局部变量
    //C++11:auto:类型推导,实现高效编程

    auto ch1 = 'a';
    auto str = "hello world";
    auto d = 1.12345;
    string s1 = "hello";
    string::iterator it = s1.begin(); 
    auto it2 = s1.begin();

    //using关键字的升级:替代C语言typedef的关键字
    //typedef关键字的作用:给类型重命名的;提高代码可读性、移植性的;
     
    using Int = int;//typedef int Int;
    using Len = int;//typedef int Len;
    
    using P_FUNC = int (*)(int,int);//typedef int (*P_FUNC)(int,int);

    Int c; //int c;
    Len c2;

    add(6,5);
    P_FUNC p_func = add;//int (*p_func)(int,int) = add;
    p_func(6,5);

    //C++对C的升级:类型的升级

    //引入了bool类型

    bool flag = false;
#endif
#if 0
    //引入了“引用”
    //引用:给变量起别名,定义引用必须初始化,一旦绑定就不能再次绑定到其他变量上;
    //作用:解决函数传值和传地址问题;
    //应用场景:作为函数的形参; 作为函数的返回值(函数的调用可以做左值)
    //常引用:const修饰的引用; 绑定常量
    
    int temp = test();
    test() = 10;
    test();

    int left = 5;
    int right = 6;

    int &l_left = left;

    cout << left << endl;

    swap(left,right);

    cout << left << " " << right;

    int count = 5;

    const int &l_count = 5;

    func(5,6);
#endif
    //C++11引用的分类:左值引用(&):只能绑定左值、右值引用(&&):只能绑定在右值
    //左值:可以取地址可以修改  右值:不能取地址,不能修改
    //std::move()将左值转换为右值
    //为什么引用右值引用? 实现对象移动,解决临时对象拷贝开销的问题;

    int num = 5;

    int &l_num = num;//左值引用
    int &&r_num = 5;//右值引用

    int &&r_num2 = std::move(num);//
//作用:
    //引用是不是数据类型?(不是)它占不占用内存空间?(运行时不占用内存空间,编译时预留内存空间)!!!
    //指针和引用的区别?
    //什么是对象移动?对象移动的作用?·

      //C++ maloc\free
    //new delete
    char *ptr = new char[100];
    char *ptr1 =  new char('a');
    int *p = new int (5);

    delete []ptr;
    delete ptr1;

    ptr = nullptr;
    ptr1 = nullptr;

    //malloc free   vs   new  delete

    add(6,5);
    add(6,5);

    return 0;
}

二.结构体升级,string类,vector,强制类型转换

2、结构体的升级
(1)定义方式不同:
C中定义:strcut Student stu;
C++中定义:Student stu;
(2)结构体中可以保存函数
(3)可以设置权限
public:可以在结构体内外访问
private/protected:只能在结构体内访问
(4)可以继承
(注)class VS struct
区别
默认访问权限:class 默认private struct默认public
命名:class(类) struct(结构体) class定义称之为对象 struct定义称之为变量
类内实现的方法,编译器会优化为inline函数,所以成员方法最好类外实现
为什么引用类?
具有封装性(保证代码功能的独立:设置访问权限)->提高代码维护性

#include <iostream>
#include <string.h>

using namespace  std;

//class vs struct
//different:
//read permission:class 默认 private   struct默认public
//name: class  struct    class 对象  struct 结构体
//引入类:封装性(保证代码独立,设置访问权限)--提高维护性




struct Person    //class Person
{
    void printhello()
    {
        cout<<"hello"<<endl;
    }
};

class  Student //struct
{
    //update3:setting read permission:      public\private\protected
//类内实现的方法,编译器会优化为inline函数
//成员方法类外实现
public:
    int num;
    char  name[20];
    int age;   //成员变量
public:
    //update2:save func
    void print(){    //成员方法
        cout<<"num="<<num<<endl;
    }

};

int main()
{
    //update1 :define type
    Student stu;
    stu.num = 1;
    stu.age = 20;
    strcpy(stu.name,"zhangsan");

    stu.print;

    return 0;
}

student.cpp

#include "student.h"

int main()
{
    Student::print;

    return 0;
}

student.h

#pragma once

#include <iostream>

using namespace  std;

class  Student //struct
{
public:
    int num;
    char  name[20];
    int age;   //成员变量
public:
    void print(){    //成员方法
        cout<<"num="<<num<<endl;
    }
};

(五)string类
1、定义并初始化
string s1 = “hello world”;
2、属性
cout << s1.size() << endl;返回有多少个字符
cout << s1.length() << endl;长度=size
3、遍历
(1)支持数组的访问方式
(2)通过函数访问
区别:
[ ]不会检查后是否越界
at检查:如果越界,产生异常->更加安全
for函数:
foeach函数:
迭代器(类似于指针):
获取指向第一个字符的迭代器
获取指向最后一个字符的迭代器
正向迭代器:
反向迭代器:

在这里插入图片描述

4、插入
string &insert(int p0, const char *s);
string &insert(int p0, const char *s, int n);
string &insert(int p0,const string &s);
string &insert(int p0,const string &s, int pos, int n);
//前4个函数在p0位置插入字符串s中pos开始的前n个字符
string &insert(int p0, int n, char c);//此函数在p0处插入n个字符c
iterator insert(iterator it, char c);//在it处插入字符c,返回插入后迭代器的位置
void insert(iterator it, const_iterator first, const_iterator last);//在it处插入[first,last)之间的字符
void insert(iterator it, int n, char c);//在it处插入n个字符c

5、删除
iterator erase(iterator first, iterator last);//删除[first,last)之间的所有字符,返回删除后迭代器的位置
iterator erase(iterator it);//删除it指向的字符,返回删除后迭代器的位置
string &erase(int pos = 0, int n = npos);//删除pos开始的n个字符,返回修改后的字符串

6、替换
string &replace(int p0, int n0,const char *s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const char *s, int n);//删除p0开始的n0个字符,然后在p0处插入字符串s的前n个字符
string &replace(int p0, int n0,const string &s);//删除从p0开始的n0个字符,然后在p0处插入串s
string &replace(int p0, int n0,const string &s, int pos, int n);//删除p0开始的n0个字符,然后在p0处插入串s中从pos开始的n个字符
string &replace(int p0, int n0,int n, char c);//删除p0开始的n0个字符,然后在p0处插入n个字符c
string &replace(iterator first0, iterator last0,const char *s);//把[first0,last0)之间的部分替换为字符串s
string &replace(iterator first0, iterator last0,const char *s, int n);//把[first0,last0)之间的部分替换为s的前n个字符
string &replace(iterator first0, iterator last0,const string &s);//把[first0,last0)之间的部分替换为串s
string &replace(iterator first0, iterator last0,int n, char c);//把[first0,last0)之间的部分替换为n个字符c
string &replace(iterator first0, iterator last0,const_iterator first, const_iterator last);//把[first0,last0)之间的部分替换成[first,last)之间的字符串

7、查找
8、比较

#include <iostream>
#include <string.h>

using namespace std;

int main ()
{
    const char *ptr = "hello world";
    char src[20]="hello world";

//1 定义并初始化
    string s1= "hello world";
    string s2('a',100);
    string s3("hello world");
    string s4="";

#if 0
//2属性
    if(s4.empty()==true)
    {
        cout <<"s4 is empty"<<endl;
    }
    cout<<s1.size()<<endl;//返回多少个字符
    cout<<s1.length()<<endl;//length=size

//3遍历
    cout <<s1[0]<<endl; //支持数组的访问方式
    cout<<s1.at(0)<<endl; //at  hanshu
    //区别:[]不会检查是否越界  at检查:如果越界,产生异常
    //cout<<s1[100]<<endl;
    //cout<<s1.at(100)<<endl;//safe

    for(int i=0;i<s1.size();i++)
    {
        cout<<s1[i];//s1.at(i)
    }
    putchar('\n');

    for(auto temp:s1)
    {
        cout<<temp;
    }
    putchar('\n');

    //迭代器:指针类型
    //迭代器类型:string::iterator

    //string::iterator it;
    //it = s1.begin();//获取指向di一个字符的迭代器
    //it = s1.end(); //获取指向最后一个字符的下一个空间的迭代器('\0')
    //正向迭代器反向
    for(auto it = s1.begin();it !=s1.end();it++)
    {
        cout<<*it;
    }
    putchar('\n');
    //反向迭代器
    for(auto it = s1.rbegin();it !=s1.rend();it++)
    {
        cout<<*it;
    }
    putchar('\n');
#endif
//insert
    //s1.insert(2,"jsetc");
    //cout<<s1<<endl;   //hejsetcllo world

    string temp="jsetc";
    string::iterator it;
    for(it=s1.begin();it!=s1.end();it++)
    {
        if(*it=='e')
        {
            break;
        }
    }
    s1.insert(++it,temp.begin(),temp.end()); 

//delete
    for(it=s1.begin();it!=s1.end();it++)
    {
        if(*it=='l')
        {
            //break;
            s1.erase(it);
        }
        else
        {
            it++;
        }
    }
    //s1.erase(it);   

//replace
    //s3.swap(s4);
    s3.replace(s3.begin(),s3.end(),s4.begin(),s4.end());
    cout<<"s3="<<s3<<endl;
    cout<<"s4="<<s4<<endl;

//find
    string::size_type t;
    if( (t=s1.find('z') ) == string::npos )
    {
        cout <<"not find z\n";
    }
    cout<<"t = "<<t<<endl;

//compare





    return 0;
}


vector
    //vi插入10个整数,删除里面的奇数,然后输出结果
#include <iostream>
#include <vector>
#include <string.h>
#include <stdio.h>

using namespace std;

int main()
{
    vector<int> vi ;
    
    int a ;
    for(int i=0;i<5;i++)
    {
        scanf("%d",&a);
        vi.push_back(a);
    }
    //vector<int>::iterator it;
    for(auto it=vi.begin();it !=vi.end();)
    {
        if((*it)% 2 != 0)
        {
            vi.erase(it);
        }
        else{
            it++;
        } 
    }

    for(auto it=vi.begin();it !=vi.end();it++)
    {    
        cout<<*it<<"  ";
    }
    putchar('\n');

    return 0;
}

    //vs插入5个字符串,删除字符串中后缀为奇数的字符串,然后输出结果
#include <iostream>
#include <string.h>
#include <vector>

using namespace std;

int main()
{
    vector<string> vs;

    string str;
    for(int i=0;i<5;i++)
    {
        cin>>str;
        /*
        auto it=str.end()-1;
        if( (*it)%2 == 0 )
        */
        vs.push_back(str);      
    }
/*
    for(auto it=vs.begin();it!=vs.end();it++)
        cout<<*it<<"  ";
    putchar('\n');
*/
    for(auto it=vs.begin();it!=vs.end();it++)
    {
        auto itt=(*it).end()-1;
        if( (*itt)%2 == 0  )
            cout<<*it<<" ";
    }
    putchar('\n');

    return 0;
}

    //把I am from shanghai逆序为shanghai from am I
#include <iostream>
#include <string.h>
#include <vector>

using namespace std;

int main()
{
    vector<string> vs;

    string str;
    for( int i =0; i<4 ; i++ )
    {
        cin>>str;
        vs.push_back(str);      
    }

    for(auto it=vs.rbegin() ; it!=vs.rend() ; it++)
    {
        cout<<*it<<" ";
    }
    putchar('\n');
    

    return 0;
}

(六)C++独有的类型的转换
隐式转换和显式转换
(1)static_cast:相关类型转换(隐式类型转换),父类和子类,void *和其他类型指针的转换。
优点:做类型检查(检查类型是否可以转换)
(2)reinterpret_cast:相当于C语言的强制类转换,可以将任意指针类型进行转换。
(3)const_cast:将指针或者引用的const属性去除。

#include <iostream>

using namespace std;

int main()
{
    //c++类型转化
    //static_cast:相关类型转换,父类和子类,void* 和其他类型指针转换

    int num = 5;
    double b = static_cast<double>(num);
    char ch = static_cast<char>(num);

    int *p_num = &num;
    void *p = p_num;
    int *p_num2 =  static_cast<int*>(p);   //(int *)p;

    //优点:检查类型是否keyi转换
    //char *ptr = static_cast<char *>(p_num);  //error
    //reinterpret_cast相当于c语言的强制类型转换,可以将任意类型指针进行转换
    char *ptr = reinterpret_cast<char *>(p_num2);

    //const_cast把指针或引用的const去除
    const int n=5;
    const int *p_n = &n;

    int *temp = const_cast<int *>(p_n);

    //dynamic_cast多态


    return 0;
}

三.构造函数,友元函数,初始化表,静态成员变量

构造函数:
1.函数名和类名相同
2.无返回值
特点:1.构造函数允许重载
2.每一个类都有自带的默认构造函数
3.一旦自己定义了构造函数,会将原本的默认构造函数覆盖
4.类的对象作为参数传入,会调用复制构造函数,会创建新的对象

this指针
构造函数的返回值:构造函数返回对象本身
类complex的复制构造函数不能带有complex类型的参数

当类没有复制构造函数的时候,=的作用就只是引用
匿名对象:生命周期只存在于创建的那一行
析构函数
friend关键字:友元函数,调用类的成员方法

函数:malloc 在堆上进行申请空间不会调用构造函数和析构函数
关键字:new delete 创建时会自动调用构造函数和析构函数

初始化表:const修饰的成员变量只能在初始化表进行初始化
void show( const complex & s1 )形参s1不可被修改
const int show (complex & s1)返回值不可被修改
int show (complex & s1)const 常成员函数,该函数内不可修改任何成员变量

static修饰成员变量:
1.静态成员不占用对象空间
2.静态成员属于整个类,整个类(所有对象)共享这个静态变量
3.静态成员变量定义必须初始化,必须在类外初始化
4.静态成员函数:操作静态成员变量,不能操作其他变量

完善虚数类

#include <iostream>
#include <stdio.h>

using namespace std;

class  complex
{
    public:
        complex( int real,int vur );
        complex();
        friend void show(const complex &s1); //友元函数
        void show2(complex &s1)const;
        complex ( const complex &s1 ); //类complex的复制构造函数不能带有complex类型的参数
        complex & add( complex &s1 );
        ~complex();//析构函数
        static void showstatic();

    private:
       int real;
       int vur; 
        static int count; 

};

int complex::count = 0; //静态成员变量定义必须初始化,必须在类外初始化

void complex::showstatic()
{
    cout<<count<<endl;
}

void complex::show2(complex &s1)const
{
    //this->real ++; //error
}

complex::complex( int real,int vur )
        {
            cout<<"number  constructor"<<endl;
            this->real  =  real;
            this->vur = vur;
        }

complex::complex()
        {
            cout<<"no number  constructor "<<endl;
            count++;
        }

void show( const complex & s1 )
        {
            cout<<s1.real<<"+"<<s1.vur<<"i"<<endl;
        }

complex::complex ( const complex &s1 ): real(real) ,vur(vur)   //const int vur
        { //类complex的复制构造函数不能带有complex类型的参数
            cout<<"copy  constructor"<<endl;
            //this->real = s1.real;
            //this->vur = s1.vur;
        }

complex &  complex::add( complex &s1 )
        {
            static complex s2 ;
            s2.real=this->real + s1.real ;
            s2.vur=this->vur + s1.vur;
            return s2;
        }

complex::~complex()//析构函数
        {
            cout<<"disconstructor  complete"<<endl;
        }

int main()
{
/*
    complex  s1(1,2);//有参构造函数
    //s1.show();

    complex s2;//无参构造函数

    complex s3(s1);//复制构造函数
    s3.show();

    complex s4 =s1;//当类没有复制构造函数的时候,=的作用就只是引用
    s4.show();
*/
/*
    complex  s1(1,2);
    complex s2(2,3);
    complex s3;
    s3=s2.add(s1);
    s3.show();
*/
    
    //complex(3,4); //匿名对象,生命周期只存在于创建的那一行

/*
    complex *t1 = (complex * )malloc (sizeof(complex) ); //在堆上进行申请空间不会调用构造函数
    free(t1);
*/
/*
    complex *t1 = new complex (1,2) ;
    complex *t2 = new complex (1,2) ;
    complex *t3 = new complex;
    show(*t1);
    *t3=t1->add(*t2);
    show(*t3);
    delete(t1);
    delete(t2);
    delete(t3);

    int *a = new int[10];
*/
/*
    complex s1;
    complex s2;
    //cout<<complex::count<<endl;
    s1.showstatic();
*/
    //完善虚数类

    return 0;
}

四.继承,多态,纯虚函数

继承:class 子类 : 修饰符 父类
public:公有继承
protected:所有都为保护
private:所有为私有
1.基类的私有成员变量,继承这个类也无法访问这个私有成员变量。private成员变量只在本类中可使用
2.protect和public的成员变量,在子类中也可访问
3.private继承的子类无法调用父类中public的方法和变量
4.私有成员被继承,它占用内存空间,不可见不可操作
5.在派生类中,不会用到基类的方法,名字遮蔽原则
基类和派生类的方法不会构成重载,名字相同就被遮蔽

#include  <iostream>
using namespace  std;

class  People
{
    public:
        void  setname(const  char*name);
        void  setage(int age);
        const char * getname();
        int getage();
        void display();
    private:
        int m_age;
        const char * m_name;
};

void People::display()
{
    cout<<"name= "<<getname()<<"\nage= "<<getage()<<endl;
}

void  People::setname(const  char * name){ m_name = name;   }
void People::setage(int age){  m_age = age;}
const char * People::getname(){  return m_name;}
int  People::getage(){ return   m_age;}

class  Student:public People    //公有继承
{
    public:
        void  setscore(float  score);
        float getscore();
    private:
    float m_score;
};

void Student::setscore(float score){ m_score = score;}
float  Student::getscore(){ return m_score;}

class  midStu:public Student
{
    public:
        void setrank(int rank);
        int display();
    private:
        int m_rank;
};

void midStu::setrank(int rank){m_rank = rank;}
int  midStu::display()
{
    cout<<" name = "<<getname()<<"\n age = "<<getage()<<" \n score = "<<getscore()<<"\n rank = "<<m_rank <<endl;
}

int main ()
{
    midStu stu1;
    stu1.setname("xiangming");
    stu1.setage(20);
    stu1.setscore(90.0f);
    stu1.setrank(5);
    stu1.display();

    People peo1;
    peo1.setname("sb");
    peo1.setage(18);
    peo1.display();


    return 0;
}

6.派生类的构造函数中允许调用基类的构造函数,但仅限于参数的初始化表

#include <iostream>
using namespace std;
class People
{
    public:
        People(int age,const char * name);
        void show();
        const char* getname();
        int getage();
    private:
        int m_age;
        const char * m_name;
};

People::People(int age,const char * name):m_name(name),m_age(age)
{
}
const char* People::getname(){ return m_name;}
int People::getage(){  return m_age;}
void People::show()
{
    cout<<"name = "<<getname()<<"\nage = "<<getage()<<endl;
}

class Student:public People
{
    public:
        Student(const char * name,int age,float score);
        void show();
    private:
        float m_score;
};

Student::Student(const char * name,int age,float score):People(age,name),m_score(score)
{}
void Student::show()
{
    cout<<"name is"<<getname()<<",age is"<<getage()<<",age score "<<m_score<<endl;
}

int main()
{
    Student stu1("xm",15,80.5f);
    stu1.show() ;
    stu1.People::show(); //调用父类的方法


    return 0;
}

7.继承的构造函数和构析函数的调用顺序,ABCCBA

#include <iostream>
using namespace std;

class A
{
    public:
        A( )
        {
            cout<<"A  constructor"<<endl;
        }
        ~A()
        {
            cout<<"A disconstructor"<<endl;
        }
};

class B:public  A
{
    public:
    B()
    {
        cout<<"B constructor"<<endl;
    }
    ~B()
    {
        cout<<"B disconstructor"<<endl;
    }
};

class C:public B
{
    public:
    C()
    {
        cout<<"C constructor"<<endl;
    }
    ~C()
    {
        cout<<"C disconstructor"<<endl;
    }
};

int main()
{   
    C test;
    return 0;
}

8.继承的构造函数的调用顺序,只和继承的顺序有关

#include <iostream>
using namespace std;

class BaseA
{
    public :
        BaseA(int a,int b);
        ~BaseA();
        void show()
        {
            cout<<m_a<<" "<<m_b<<endl;
        }
        protected:
            int m_a;
            int m_b;
};

BaseA::BaseA(int a,int b):m_a(a),m_b(b)
{
    cout<<"A  constructor"<<endl;
}
BaseA::~BaseA()
{
    cout<<"A disconstructor"<<endl;
}

class BaseB
{
    public:
        BaseB(int c,int d);
        ~BaseB();
        void show()
        {
            cout<<m_c<<" "<<m_d<<endl;
        }
    protected:
        int m_c;
        int m_d;
};

BaseB::BaseB(int c,int d):m_c(c),m_d(d)
{
    cout<<"B  constructor"<<endl;
}
BaseB::~BaseB()
{
    cout<<"B disconstructor"<<endl;
}

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

C::C(int a,int b,int c,int d,int e):BaseA(a,b),BaseB(c,d),m_e(e)
{
    cout<<"C constructor"<<endl;
}
C::~C()
{
    cout<<"C disconstructor"<<endl;
}

int main()
{
    C obj(1,2,3,4,5);
    obj.show();

    return 0;
}

9.菱形继承,命名冲突
虚继承:派生类中只留下一份间接基类的成员 virtual
向上转型:只能把派生类对象赋值给基类对象

#include <iostream>
using namespace std;

class A
{
    protected:
        int m_a;
};
class B:virtual public A    //虚继承
{
    protected:
        int m_b;
};
class C:virtual public A    //虚继承
{
    protected:
        int m_c;
};
class D:public B,public C
{
    public:
        void seta(int a)
        {                               
            m_a = a;            // m_a=a; 命名冲突
        }
    protected:
        int m_d;
};


int main()
{
    D d;

    return 0;
}
#include <iostream>
using namespace std;

class A
{
    public:
        A(int a):m_a(a){}
        void display()
        {
            cout<<"A:"<<m_a<<endl;
        }
    protected:
        int m_a;
};

class B:public A
{
    public:
        B(int a,int b):A(a),m_b(b){}
        void display()
        {
            cout<<"B:"<<m_a<<","<<m_b<<endl;
        }
    public:
        int m_b;
};

class C
{
    public:
        C(int c):m_c(c){}
        void display()
        {
            cout<<"C:"<<m_c<<endl;
        }
    protected:
        int m_c;
};

class  D:public  B,public  C
{
    public:
        D(int a,int b,int c,int d):B(a,b),C(c),m_d(d){}
        void display()
        {
            cout<<"D:"<<m_a<<","<<m_b<<","<<m_c<<endl;
        }
    private:
        int  m_d;
};


int main()
{
    A *pa= new A(1);
    B *pb= new B(10,20);
    C *pc= new C(30);
    D *pd= new D(100,200,300,400);
    pd->display();

    pa = pd;        //向上转型  只能把派生类对象赋值给基类对象
    pa->display();

    pa = pb;        //向上转型
    pa->display();

    pc = pd;
    pc->display();


    float a = 10;
    printf("%f\n",a);

    return 0;
}

多态:一个接口,多种方法(代码的复用性)(一行相同的代码,实现不同的功能)
1.重写:子类的同名函数,遮蔽父类的同名函数
2.虚函数:在需要修饰的函数前加virtual
3.基类的指针只能调用基类的方法

#include <iostream>
using namespace std;

class people
{
    public:
        people(const char * name,int age);
        virtual    void display();  //虚函数
    protected:
        int m_age;
        const char * m_name; 
};

people::people(const char * name,int age):m_name(name),m_age(age) {}

void people::display()
{
    cout<<m_name<<" age:"<<m_age<<endl;
}

class teacher :public  people
{
    public:
        teacher(const char *name ,int age,int salary):people(name,age),m_salary(salary)  {}
        void   display()
        {
            cout<<m_name<<" age:"<<m_age<<",salary :"<<m_salary<<endl;
        }
        protected:
            int m_salary;
};

int main()
{
    people  *p = new people("xm",23);
    p->display();

    p = new teacher("xg",45,4000);                //基类的指针只能调用基类的方法
    p->display();                        //多态

    return 0;
}

4.虚函数指针和虚函数表
被命名为virtual 派生类中所有的同名函数,自动变为虚函数

#include <iostream>
using namespace std;

class   Base
{
    public :
        virtual   void  func();
        virtual   void  func(int);  
};

void Base::func()
{
    cout<<"void Base::func()"<<endl;
}
void  Base::func(int n)
{
    cout<<"void Base::func(int) \n";
}

class  Derived  :public Base
{
    void  func();
    void  func(char *);
};

void Derived::func()
{
    cout<<"void Derived::func() \n";
}
void Derived::func(char *str)
{
    cout<<"void Derived::func(char *str) \n";
}


int main()
{
    Base  *p= new Derived();    //创建一个基类指针指向子类对象
    p->func();
    p->func(10);
    //p->func("hello");
    
    

    return 0;
}

5.构成多态的条件
(1)必须存在继承关系
(2)继承关系中必须有同名的虚函数
(3)存在基类的指针,通过该指针,调用虚函数
必须是基类定义的函数才能实现,注意函数重载的区别和特点

纯虚函数 virtual = 0 ;
1.没有函数体
2.纯粹的函数声明
3.包含纯虚函数的类称为抽象类:无法实例化的类
4.抽象类称为模板类,一般作为基类存在
一个类想要实例化,就要将所有继承来的纯虚函数全部重写

#include <iostream>
using namespace std;

class Line  //线
{
    public:
        Line(float len);
        virtual float   area() = 0;             //此纯虚函数作为抽象模板存在,没有办法实例化
        virtual float   volume() = 0;
    protected:
        float m_len;
};

Line::Line(float len):m_len(len)
{
}

class  Rec:public Line  //矩形
{
    public:
        Rec(float len,float width);
        float area();
    protected:
        float m_width ;
};

Rec::Rec(float len,float width):Line(len),m_width(width)
{
}
float Rec::area()
{
    return  m_width*m_len;
}

class  Cubiod:public  Rec       //长方体
{
    public:
        Cubiod(float len,float width,float height);
        float area();
        float volume();
    protected:
        float   m_height;
};

Cubiod::Cubiod(float len,float width,float height):Rec(len,width),m_height(height)
{
}
float   Cubiod::area()
{
    return  m_height*m_len*2+m_len*m_width*2+m_width*m_height*2;
}
float   Cubiod::volume()
{
    return  m_height*m_len*m_width;
}

class Cube:public Cubiod        //正方体
{
    public:
        Cube(float len);
};

Cube::Cube(float len):Cubiod(len,len,len)
{
}

int main()
{
    Line *p = new Cubiod(2,3,4);
    cout<<"cubiod area: "<<p->area() <<endl;
    cout<<"cubiod volume : "<<p->volume()<<endl;

    p = new Cube(5);
    cout<<"cube area: "<<p->area() <<endl;
    cout<<"cube volume : "<<p->volume()<<endl;





    return 0;
}

完善三维空间内的表面积和体积的项目(圆形和球,三角形和棱柱体)

注意点:

typeid()
tupeid(data Yype)
typeid(expression)
三目运算符(a>b a:b)=90; 常量不能作为左值

c语言默认const为外部连接,c++默认外部连接
引用(实际上占内存空间)
引用必须初始化,指针可以不初始化

重写:
1.在不同类内
2.关键字:virtual
3.参数列表:一样

重载:int swap(int a,int b) int swap(float a,float b)
1.在一个类内
2.关键字:只检查参数
3.参数列表:必须不一样

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

家住隔壁我姓王8

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

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

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

打赏作者

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

抵扣说明:

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

余额充值