2024年物联网嵌入式最新小甲鱼C++快速入门学习笔记_小甲鱼c++快速入门笔记,从草根到百万年薪程序员的十年风雨之路

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

using namespace std;

int main()//ofstream 为构造函数 
{
      ofstream out( “test.txt”, ios::app );// app表示以添加形式(即不覆盖原数据)打开

if( !out )
      {
            cerr << “文件打开失败!” << endl;
            return 0;
      }

for( int i=10; i > 0; i-- )
      {
            out << i;
      }

out << endl;
      out.close();

return 0;
}

实例4:同时完成对test.txt的读写

#include
#include

using namespace std;

int main()
{
      fstream fp(“test.txt”, ios::in | ios::out );
      if( !fp )
      {
            cerr << “打开文件失败!” << endl;
            return 0;
      }

fp << “IloveFishc.com!IloveFishc.com!”;

static char str[100];

fp.seekg(ios::beg); //使得文件指针指向文件头   ios::end则是文件尾。
      fp >> str;
      cout << str << endl;

fp.close();

return 0;
}

作业:将text1.txt文件内容复制到text2.txt中

#include //涉及到了文件流操作 
#include

using namespace std;

int main()
{
    ifstream in;
    ofstream out;
    char x;
    in.open(“text1.txt”);
    out.open(“text2.txt”);
    while(!in)
             {
                 cout<<“源文件打开失败,请重新输入路径:”;
                 return 0;
              }
     while(!out)
             {
                 cout<<“目标文件失败,请重新输入路径:”;
                 return 0;
             }
    while(in>>x)
        {
                  out<<x;
         }
     out<<endl;
     in.close();//关闭文件 
     out.close();//关闭文件 
     system(“pause”);
     return 0;

}

第五讲:输入输出小结

实例1:根据输入内容输出

#include 
using namespace std;//名字空间
int main()
{
    char answer;
    
    cout << “请问可以格式化您的硬盘吗?!【Y/N】” << “\n”;
    cin >> answer;
    
    switch(answer)
    {
        case’Y’:
        case’y’:
            cout <<“随便格式化硬盘是不好的,会让妈妈骂的~”<<“\n”;
            break;
        case’N’:
        case’n’:
            cout << “您的选择是明智的!” << “\n”;
            break;
        default: 
            cout << “您的输入不符合要求!!!” << “\n”;
            break;    
    }
    std::cin.ignore(100,‘\n’);//忽略带回车的100个输入字符 
    
    std::cout << “输入任何字符结束程序!” << “\n”;
    std::cin.get();
    
    return 0; 
}

实例2:摄氏、华氏温度转换

//温度转换  华氏温度 = 摄氏温度 * 9.0/5.0 + 32 
//const与define作用相同,都为定义常亮,但尽量用const 
#include
using namespace std;
int main()
{
    const unsigned short ADD_SUBTRACT = 32; 
    const double RATI0 = 9.0 / 5.0;
    
    double tempIn,tempOut;//输入输出数据 
    char typeIn,typeOut;//输入输出类型(摄氏度F或华氏温度C) 
    
    std::cout << “请亲们以【xx.x C】或者【xx.x F】格式输入一个温度:”;
    std::cin >> tempIn >> typeIn;
    switch(typeIn)
    {
        case ‘c’:
        case ‘C’:
            tempOut = tempIn * RATI0 +32;
            typeIn = ‘C’;
            typeOut = ‘F’;
            break;
        case ‘f’:
        case ‘F’:
            tempOut = (tempIn - 32)/RATI0;
            typeIn = ‘F’;
            typeOut = ‘C’;
            break;
        default:
            typeOut = ‘E’;
    }  
    if(typeOut != ‘E’)
    {
        cout <<“\n”<< tempIn << typeIn << " = " << tempOut << typeOut << “\n\n”;
    }
    else
    {
        cout << “输入错误!\n”; 
        
    }
    
    cin.ignore(100,‘\n’);//忽略带回车的100个输入字符
    std::cout << “输入任何字符结束程序!” << “\n”;
    std::cin.get();
    
    return 0;
 }

第六讲:函数的重载

函数重载:实质就是用同样的名字再定义一个有着不同参数类型及个数来实现不同操作的函数。

实例1:改变同一函数的输入参数类型

#include

void convertTemperature(double tempIn, char typeIn);
void convertTemperature(int tempIn, char typeIn);

int main()
{
    double tempIn;
    int tempInInt;
    char typeIn;

std::cout << "请以【xx.x C】或【xx.x F】的形式输入温度: ";
      std::cin >> tempIn >> typeIn;
      std::cin.ignore(100, ‘\n’);
      std::cout << “\n”;
    convertTemperature(tempIn, typeIn);

std::cout << "请以【xx C】或【xx F】的形式输入温度: ";
      std::cin >> tempInInt >> typeIn;
      std::cin.ignore(100, ‘\n’);
      std::cout << “\n”;
    convertTemperature(tempInInt, typeIn);

return 0;
}

void convertTemperature(double tempIn, char typeIn)
{     
      const unsigned short ADD_SUBTRACT = 32;
      const double RATIO = 9.0 / 5.0;
      
      double tempOut;
      char typeOut;      
      
      switch( typeIn )
      {
      case ‘C’:
      case ‘c’:
            tempOut = (tempIn * RATIO) + ADD_SUBTRACT;
            typeOut = ‘F’;
            typeIn = ‘C’;
            break;

case ‘F’:
      case ‘f’:
            tempOut = (tempIn - ADD_SUBTRACT) / RATIO;
            typeOut = ‘C’;
            typeIn = ‘F’;
            break;

default:
            typeOut = ‘E’;
            break;                  
      }

if( typeOut != ‘E’ )
      {
            std::cout << tempIn << typeIn << " = " << tempOut << typeOut << “\n\n”;
      }
      else
      {
            std::cout << “请按照给出格式输入!” << “\n\n”;
      }

std::cout << “请输入任意字符结束!” << “\n”;
      std::cin.get();
}

void convertTemperature(int tempIn, char typeIn)
{     
      const unsigned short ADD_SUBTRACT = 32;
      const double RATIO = 9.0 / 5.0;
      
      int tempOut;
      char typeOut;      
      
      switch( typeIn )
      {
      case ‘C’:
      case ‘c’:
            tempOut = (tempIn * RATIO) + ADD_SUBTRACT;
            typeOut = ‘F’;
            typeIn = ‘C’;
            break;

case ‘F’:
      case ‘f’:
            tempOut = (tempIn - ADD_SUBTRACT) / RATIO;
            typeOut = ‘C’;
            typeIn = ‘F’;
            break;

default:
            typeOut = ‘E’;
            break;                  
      }

if( typeOut != ‘E’ )
      {
            std::cout << tempIn << typeIn << " = " << tempOut << typeOut << “\n\n”;
      }
      else
      {
            std::cout << “请按照给出格式输入!” << “\n\n”;
      }

std::cout << “请输入任意字符结束!” << “\n”;
      std::cin.get();
}

作业:calc()传入不同数目的参数时,不同运算的运用

#include

double calc(double tempIn);//计算该参数平方值 
double calc(double tempIn, double tempIn2);//计算两个参数的积 
double calc(double tempIn, double tempIn2, double tempIn3);//计算三个参数的和

int main()
{
    double tempIn,tempIn2,tempIn3;
    int number; 
    double tempOut;

std::cout << "请输入数据个数: ";
    std::cin >> number;
   
    std::cout << "请以【xx xx】形式输入具体数据: ";  
    switch(number)
    {
        case 1:
            std::cin >> tempIn;
            tempOut = calc(tempIn);
            break;
        case 2:
            std::cin >> tempIn >> tempIn2;
            tempOut = calc(tempIn, tempIn2);
            break;
        case 3:
            std::cin >> tempIn >> tempIn2 >> tempIn3;
            tempOut = calc(tempIn, tempIn2, tempIn3);
            break;
        default:
            std::cout << “错误!”;
            break; 
    }
    std::cout << “计算结果为:” << tempOut << “\n”;
     
    std::cin.ignore(100, ‘\n’);
    std::cout << “\n”;

return 0;
}

double calc(double tempIn)
{
    return tempIn*tempIn;
}

double calc(double tempIn, double tempIn2)
{
    return tempIn*tempIn2;
}

double calc(double tempIn, double tempIn2, double tempIn3)
{
    return (tempIn + tempIn2 + tempIn3);
}

第七讲:复杂的数据类型

数组:可以把许多个同类型的值存储在同一变量名下

实例1:输入的数据存储到数组中,并计算其和与平均值输出

#include

using namespace std;//使用作用域

int main()
{
    int array[10];
    int i;
    int sum=0;
    double average;
    
    cout << “请输入10个整数!\n”; 
    for(i=0;i<10;i++)
    {
        cout << “请输入第” << i+1 << “个整数:”;
        cin >> array[i];
        sum+=array[i];
     }
     average = sum/10.0; 
     cout << “和为:” << sum << “\n” << “平均值为:” << average << “\n”;  
     
    return 0;
}

实例2:打印出用户输入的字符串

#include
#include

using namespace std;

int main()
{
    string str;
    cout << “请输入一个字符串:”;
    getline(cin, str);//getline为获取一行数据  cin >> str使用时遇到空格便默认输入接收 
    cout << str;
    
    return 0; 
 }

实例3:实例1的规范改进

#include
//未完善 
using namespace std;//使用作用域 
//当输入错误时,cin会返回错误0 
#define ITEM 10
int main()
{
    int array[ITEM];
    int i;
    int sum=0;
    double average;
    
    cout << “请输入” << ITEM << “个整数!\n”; 
    for(i=0;i<ITEM;i++)
    {
        cout << “请输入第” << i+1 << “个整数:”;
        while(!(cin >> array[i])) //输入非法时是下一次输入时才进入循环 
        {
            cin.clear();//清楚不规范输入值 
            cin.ignore(100,‘\n’);
            cout << “\n请输入一个合法的值!”;
            cout << “\n请重新输入第” << i+1 << “个整数:\n”; 
            cin >> array[i];
        }
        sum+=array[i];
     }
     average = (double)sum/ITEM; 
     cout << “和为:” << sum << “\n” << “平均值为:” << average << “\n”;  
     
    return 0;
}

第八讲:复杂的数据类型——指针

小知识:程序以文件的形式存储在硬盘,但它们却是在计算机的内存中运行

对于变量可以通过变量名与地址两种方式进行索引,变量的地址在程序执行期间是不会发生变换的

地址是计算机内存中的某个位置;指针是专门用来存放地址的特殊类型变量

第九讲:复杂的数据类型——指针02

指针的类型必须与由它保存其地址的变量的类型一致,当某个变量的地址给了指针p时,就可以通过*p(即表示该地址的数据)来对该变量数据进行操作

一定要牢记一个事实:指针所保存的是内存中的一个地址,它并不保存指向的数据的值本身。因此务必确保指针对应一个已经存在的变量或者一块已经分配的内存

*有两种用途,一是创建指针: int *p = &a;   另外是解引用  *p = 123;

c++允许多个指针指向同一个地址

.void *则为“无类型指针”,可以指向任何数据类型。对一个无类型指针进行解引用前必须先将他转换为一个适当的数据类型。

实例1:通过指针形式修改变量值(指针的解引用)

#include
using namespace std;

int main()
{
    int a = 123;
    float b = 3.14;
    char c = ‘c’;
    unsigned long d = 19880808;
    string e = “I love FishC!”;
    
    cout << “a的值是:” << a << “\n”;
    cout << “b的值是:” << b << “\n”;
    cout << “c的值是:” << c << “\n”;
    cout << “d的值是:” << d << “\n”;
    cout << “e的值是:” << e << “\n\n”;
    
    int *aPointer = &a;
    float *bPointer = &b;
    char *cPointer = &c;
    unsigned long *dPointer = &d;
    string *ePointer = &e;
    
    *aPointer = 456;
    *bPointer = 4.13;
    *cPointer = ‘F’;
    *dPointer = 20190525;
    *ePointer = “I love Beauty!”;
    
    cout << “a的值是:” << a << “\n”;
    cout << “b的值是:” << b << “\n”;
    cout << “c的值是:” << c << “\n”;
    cout << “d的值是:” << d << “\n”;
    cout << “e的值是:” << e << “\n\n”;
    
}

第十讲:复杂的数据类型——指针和数组

计算机是把数组以一组连续的内存块保存的。

数组的第一个元素的地址为该数组的基地址。

实例1:数组元素地址打印

#include
 
using namespace std;

int main()
{
    const unsigned short ITEMS = 5;
    int intArray[ITEMS] = {1,2,3,4,5};
    char charArray[ITEMS] = {‘F’,‘i’,‘s’,‘h’,‘C’};
    
    int *intPtr = intArray;
    char *charPtr = charArray;
    
    cout << “整型数组输出:” << ‘\n’;
    for(int i=0;i < ITEMS; i++)
    {
            std::cout << *intPtr << " at " << (intPtr) << ‘\n’;//用reinterpret_cast把指针类型强制转换为unsigned int
            intPtr++;//地址加上以其所定义的类型所占的字节 
    } 
    
    cout << “字符型数组输出:” << ‘\n’;
    for(int i=0;i < ITEMS; i++) 
    {
            cout << *charPtr << " at " << (charPtr) << ‘\n’;
        charPtr++;
    }
    return 0;
}

实例2:数组重载

#include

using namespace std;

void print(int *pBegin,int *pEnd)
{
    while(pBegin != pEnd)
    {
        cout << *pBegin;
        ++pBegin;//地址加1 
    }
}

void print(char *pBegin,char *pEnd)
{
    while(pBegin != pEnd)
    {
        cout << *pBegin;
        ++pBegin;//地址加1 
    }

int main()
{
    int num[5] = {0,1,2,3,4};
    char name[5] = {‘F’,‘i’,‘s’,‘h’,‘C’};
    
    print(num,num + 5);
    cout << ‘\n’;
    print(name,name + 5);
    cout << ‘\n’;
    
    return 0;
}

实例3:泛型数组重载

#include

using namespace std;

template //将输入参数typename的类型赋值给elemType
void print(elemType *pBegin,elemType *pEnd)
{
    while(pBegin != pEnd)
    {
        cout << *pBegin;
        ++pBegin;//地址加1 
    }
}

int main()
{
    int num[5] = {0,1,2,3,4};
    char name[5] = {‘F’,‘i’,‘s’,‘h’,‘C’};
    
    print(num,num + 5);
    cout << ‘\n’;
    print(name,name + 5);
    cout << ‘\n’;
    
    return 0;
}

第十一讲:结构

结构是一种由程序员自己定义的、由其他变量类型组合而成的数据类型。其所能包含的变量的个数是没有限制的。

实例1:简单数据库读写

#include
#include  //文件操作 
#include <windows.h>        // 为了使用Sleep()函数

struct FishOil
{
        std::string name;
        std::string uid;
        char sex;
};

bool InitFishC();
bool ReadFishC(); 
void RecordFishC();
bool WriteFishC(FishOil *OilData);

int main()
{
        int i;
        
        InitFishC();  // 初始化数据。 
        while( 1 )
        { 
                std::cout << “请选择需要进行的操作: \n”;
                std::cout << “1. 打印数据到屏幕\n”;
                std::cout << “2. 录入数据\n”; 
                std::cout << “3. 退出程序\n”; 
                std::cin >> i;
                
                switch( i )
                {
                        case 1: 
                                if( ReadFishC() )
                                        std::cout << “成功读取文件_\n\n”;
                                else
                                        std::cout << “读取文件失败T_T\n\n”;
                                break;
                        case 2:
                                RecordFishC();
                                break;
                        case 3:
                                return 0;        
                }
        }
        
        return 0;
        
}

bool InitFishC()
{
        FishOil OilInit = {“小甲鱼”, “fishc00001”, ‘M’};

if( WriteFishC(&OilInit) == false )
                std::cout << “初始化失败T_T\n”;  
}

bool ReadFishC() //读文件 
{
        std::string temp;
        std::ifstream fileInput(“FishC.txt”);
        
        if(  fileInput.is_open() )
        {
                std::cout << "\n正在输出记录数据… ";
                for( int i=0; i <= 100; i++ )      // 打印百分比 
                {
                        std::cout.width(3);
                        std::cout << i << “%”;
                        Sleep(50);
                        std::cout << “\b\b\b\b”;
                }
                std::cout << “\n\n”;

std::cout << " 姓名 " << "  身份证  " << " 性别 " << “\n\n”;
                 
                while( std::getline( fileInput, temp ) )
                {
                        std::cout << temp << "   ";
                        std::cout << “\n”;
                }
                std::cout << “\n\n”;
                
                return true;
        } 
        else
                return false;
}

void RecordFishC()//录入数据 
{
        char goon, Save;
        FishOil OilData;
        FishOil *pOilData;
        
        goon = ‘Y’;
        while( ‘Y’ == goon )
        {
                std::cout << "请输入鱼C账号: ";
                std::cin >> OilData.name;
                std::cout << “请输入鱼C身份证:”;
                std::cin >> OilData.uid;
                std::cout << “请输入性别:”;
                std::cin >> OilData.sex;
                
                std::cout << “录入成功, 请问需要保存吗?(Y/N)”;
                std::cin >> Save;         
                if( ‘Y’ == Save )
                {
                        pOilData = &OilData;
                        if( WriteFishC( pOilData ) )
                                std::cout << “成功写入文件_\n”;
                        else
                                std::cout << “写入文件失败T_T\n”;        
                }
                else
                {
                        return;
                }
                
                std::cout << “/n请问需要再次录入吗?(Y/N)”;
                std::cin >> goon; 
        }
}

bool WriteFishC( FishOil *pOilData )//写文件 
{
        std::ofstream fileOutput(“FishC.txt”, std::ios::app);  
                // std::ios::app用来说明在老数据追加新数据 
        if( fileOutput.is_open() )
        {
                fileOutput << pOilData->name << " ";
                fileOutput << pOilData->uid << " ";
                fileOutput << pOilData->sex << “\n”;
                
                fileOutput.close();
                std::cout << “数据成功保存到FishC.txt\n\n”;
                return true; 
        } 
        else
                std::cout << “保存失败T_T\n”;
                return false;         
}

第十二讲:传值、传址和传引用

实例1:值传递

#include

void changeAge(int age,int newAge); 
int main()
{
    int age = 24;//定义一个age,占一处地址 
    std::cout << “My age is " << age <<”\n";
    
    changeAge(age,age + 1);
    
    std::cout << "Now my age is " << age << “\n”;
    
    return 0;
}

void changeAge(int age,int newAge)//再定义一个age,占另一处地址 
{
    age = newAge;
    std::cout << "In this, my age is " << age << “\n”; 
}

绕开“值传递”问题的第一种方法是向函数传递变量的地址取代他的值。

实例2:指针地址传递

#include

void changeAge(int *age,int newAge); 
int main()
{
    int age = 24;//定义一个age,占一处地址 
    std::cout << “My age is " << age <<”\n";
    
    changeAge(&age,age + 1);
    
    std::cout << "Now my age is " << age << “\n”;
    
    return 0;
}

void changeAge(int *age,int newAge)//再定义一个age,占另一处地址 
{
    *age = newAge;
    std::cout << "In this, my age is " << *age << “\n”; 
}

实例3:两值互换

#include

void swap(int *x,int *y);
int main()
{
    int x,y;
    
    std::cout << “请输入两个不同的值:”;
    std::cin >> x >> y;
    
    swap(&x,&y);
    
    std::cout << “调换后输出:” << x << ’ ’ << y <<“\n\n”; 
    
}

void swap(int *x,int *y)
{
    int temp;
    temp = *x;
    *x = *y;
    *y = temp;
}

实例4:两值互换2

#include

void swap(int *x,int *y);
int main()
{
    int x,y;
    
    std::cout << “请输入两个不同的值:”;
    std::cin >> x >> y;
    
    swap(&x,&y);
    
    std::cout << “调换后输出:” << x << ’ ’ << y <<“\n\n”; 
    
}

void swap(int *x,int *y)
{
    *x ^= *y;
    *y = *x;
    *x ^= *y;
}

实例5:不用指针的两值交换

#include

void swap(int &x,int &y);

int main()
{
    int x,y;
    std::cout << “请输入两个不同的值:”;
    std::cin >> x >> y;
    
    swap(x,y);
    std::cout << “调换后输出:” << x << ’ ’ << y << “\n\n”;
    
    return 0;
}

void swap(int &x,int &y)
{
    int temp;
    temp = x;
    x = y;
    y = temp;
}

第十三讲:联合、枚举和类型别名

联合(union)与结构有很多相似之处,联合也可以容纳多种不同类型的值,但是它每次只能储存这些值中的一个(即当我们已经给联合里的一个成员赋值后,再给另一个成员赋值时,将丢弃第一个成员的值)

实例1:联合的应用

#include

union mima
{
    unsigned long birthday;
    unsigned short ssn;
    const char *pet;//将pet声明为一个指向不变字符串的指针     
};

int main()
{
    mima mima_1;
    
    mima_1.birthday = 19970328;
    std::cout << mima_1.birthday << “\n”;
    
    mima_1.pet = “Chaozai”;//为字符串指针内的数据赋值 
    std::cout << mima_1.pet << “\n”;
    std::cout << mima_1.birthday << “\n”;//由于覆盖,将输出pet中字符串存储的地址 
    
    return 0;
}

枚举(enum)类型用来创建一个可取值列表。枚举值不是字符串,编译器会按照各个枚举值在定义时出现的先后顺序把它们与0~n-1的整数(n是枚举值的总个数)分别关联起来。

实例2:枚举的应用

#include

int main()
{
    enum weekdays{Monday, Tuesday, Wednesday, Thursday, Friday};//编译后依次变为0、1、2、3、4 
    
    weekdays today;
    
    today = Monday;
    std::cout << today << “\n”;
    
    today = Friday;
    std::cout << today << “\n”;
    
    switch (today)
    {
        case Monday:
            std::cout << “hello”;
            break;
        case Tuesday:
            std::cout << “yiwofeiye”;
            break;
        default:
            std::cout << “Goodbye”;
            break;
     }
     return 0; 
 }

类型别名(typedef)可以为一个类型定义创建一个别名。例如:

定义typedef int* intPointer;后便可以使用intPointer myPointer;来定义整型指针。

第十四节:对象

对象本质上不过是一种新的数据类型。

类(class)是一个模型(就像是一张蓝图,它决定一个对象将拥有什么样的属性、功能等),且每个类跟变量一样都有一个名字。当我们为这个类创建实例的时候,也就是对象(类的具体化实现)。

类由变量(类里的变量称属性)和函数(类里的函数称方法)组成,对象将使用那些变量来存放信息,调用那些函数来完成操作。同理对象内部有变量和函数,而结构通常只由各种变量构成。

例如std::cout即为使用的是std类中的cout对象;std:string数据类型使用的是std类中的string对象

面相对象编程技术(object-oriented programming)可以说是面向过程技术(procedural programming)的替代品。

面向过程技术关注的是对数据进行处理的过程,面向对象(OOP技术)关注的是对数据进行怎样的处理。

实例1:对象应用造一辆车

#include

#define FULL_GAS 85

class Car//让我们来造辆车,定义类Car ,C++允许在类里面声明常量,但不允许对它进行赋值 
{
public:
    std::string color;
    std::string engine;
    unsigned int gas_tank;//油缸 
    unsigned int wheel;
    
    void setColor(std::string col);
    void setEngine(std::string eng);
    void setWheel(unsigned int whe);
    void filltank(int liter);//加油
    int running(void);//动
    void warning(void); 
};
void Car::setColor(std::string col) 
{
    color = col;
}
void Car::setEngine(std::string eng)
{
    engine = eng;
}
void Car::setWheel(unsigned int whe)
{
    wheel = whe;

void Car::filltank(int liter)//函数(又称方法)的定义 
{
    gas_tank += liter;
}
int Car::running(void)
{
    std::cout << “我正在以120的时速往前移动。。。\n”;
    gas_tank–;
    std::cout << "当前还剩 " << 100*gas_tank/FULL_GAS << “%” << “油量!\n”;
    
    return gas_tank; 

void Car::warning(void)
{
    std::cout << “WARNING!!” << "\n还剩 " <<  100*gas_tank/FULL_GAS << “%” << “油量!\n”;
}

int main()
{
    char i;
    Car mycar, car1;
    
    mycar.setColor(“WHITE”);
    mycar.setEngine(“V8”);
    mycar.setWheel(4);
    
    mycar.gas_tank = FULL_GAS;
    
    while(mycar.running() )
    {
        if(mycar.gas_tank < 10)
        {
            mycar.warning();
            std::cout << “请问是否需要加满油再行驶?(Y/N)\n”;
            std::cin >> i;
            if( ‘Y’== i || ‘y’ == i)
            {
                mycar.filltank(FULL_GAS); 
            }
        }
        
    }   
    return 0;
}

第十五讲:构造器和析构器

构造器和通常方法的主要区别:

1、构造器的名字必须和它所在类的名字一样

2、系统在创建某个类的对象时会第一时间自动调用这个类的构造器

3、构造器永远不会返回任何值

实例1:构造器的运用

#include

#define FULL_GAS 85

class Car//让我们来造辆车,定义类Car ,C++允许在类里面声明常量,但不允许对它进行赋值 
{
public:
    std::string color;
    std::string engine;
    unsigned int gas_tank;//油缸 
    unsigned int wheel;
    
    Car(void);//类Car的构造函数,系统会自动调用
    void setColor(std::string col);
    void setEngine(std::string eng);
    void setWheel(unsigned int whe);
    void filltank(int liter);//加油
    int running(void);//动
    void warning(void); 
};
Car::Car(void)
{
    color = “White”;
    engine = “V8”;
    wheel = 4;
    gas_tank = FULL_GAS;

void Car::setColor(std::string col) 
{
    color = col;
}
void Car::setEngine(std::string eng)
{
    engine = eng;
}
void Car::setWheel(unsigned int whe)
{
    wheel = whe;

void Car::filltank(int liter)//函数(又称方法)的定义 
{
    gas_tank += liter;
}
int Car::running(void)
{
    char i;
     
    std::cout << “我正在以120的时速往前移动。。。\n”;
    gas_tank–;
    std::cout << "当前还剩 " << 100*gas_tank/FULL_GAS << “%” << “油量!\n”;
    
    if(gas_tank < 10)
        {
            warning();
            std::cout << “请问是否需要加满油再行驶?(Y/N)\n”;
            std::cin >> i;
            if( ‘Y’== i || ‘y’ == i)
            {
                filltank(FULL_GAS); 
            }
            
            if(gas_tank == 0)
            {
                std::cout << “抛瞄中。。。。。”;
                return 0;
            }
        }
    
    return gas_tank; 

void Car::warning(void)
{
    std::cout << “WARNING!!” << "\n还剩 " <<  100*gas_tank/FULL_GAS << “%” << “油量!\n”;
}

int main()
{
    Car mycar;
    
    mycar.gas_tank = FULL_GAS;
    
    while(mycar.running())//有油则继续跑,没有油则结束
    {
        ;
    }   
    return 0;
}

在销毁一个对象时,系统会调用另一个特殊方法,即析构器。

一般来说,构造器用来完成事先的初始化和准备互作(申请分配内存);析构器用来完成事后所必须的清理工作(清理内存)

析构器不返回任何值,也不带参数

实例2:构造器与析构器的共同应用

#include
#include
#include

class StoreQuote//定义类StoreQuote 
{
public:
    std::string quote,speaker;
    std::ofstream fileOutput;//定义文件对象fileOutput 
    
    StoreQuote();//构造器 
    ~StoreQuote();//析构器
    
    void inputQuote();//名言输入 
    void inputSpeaker();//作者输入 
    bool write();//写文件 
};

StoreQuote::StoreQuote()
{
    fileOutput.open(“test.txt”, std::ios::app);//以附加(app)的形式打开文件 
}

StoreQuote::~StoreQuote()//关闭文件,释放内存 
{
    fileOutput.close();
}

void StoreQuote::inputQuote()
{
    std::getline(std::cin, quote);
}
void StoreQuote::inputSpeaker()
{
    std::getline(std::cin, speaker);
}

bool StoreQuote::write()
{
    if(fileOutput.is_open())//文件是否打开成功 
    {
        fileOutput << quote << “|” << speaker << “\n”;//写入数据 
        return true;
    }
    else
    {
        return false;
    }
}

int main()
{
    StoreQuote quote;//使用StoreQuote类定义一个对象quote 
    
    std::cout << “请输入一句名言:\n”;
    quote.inputQuote();
    
    std::cout << “请输入作者:\n”;
    quote.inputSpeaker();
    
    if(quote.write())//文件是否写入成功 
    {
        std::cout << “成功写入文件”; 
    }
    else
    {
        std::cout << “写入文件失败”; 
        return 1;
    }
    return 0;
}

第十六讲:this指针和类的继承

this指针指的是指向当前类生成的对象

继承机制使得程序员可以创建一个类的堆叠层次结构,每个子类均将继承在它的基类定义的方法和属性。

简单地说,就是通过继承机制,可以对现有的代码进行进一步扩展,并应用到新的程序中。

基类可以派生出其它的类,也称为父类或超类(如动物类)

子类是从基类派生出来的类(如乌龟类、猪类)

实例1:子类与基类的运用

#include
#include

class Animal//定义Animal类
{
public:
    std::string mouth;
    void eat();
    void sleep();
    void drool();//流鼻涕
};

class Pig:public Animal//类Pig继承于类Animal
{
public:
    void climb();
};
class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    void swim();
};

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}
void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}
void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}
int main()
{
    Pig pig;
    Turtle turtle;//定义一个对象turtle

pig.eat();
    turtle.eat();
    pig.climb();
    turtle.swim();

return 0; }第十七讲:继承机制中的构造器和析构器

实例1:构造器及其参数的继承应用

#include
#include

class Animal//定义Animal类
{
public:
    std::string mouth;
    std::string name;
    
    Animal(std::string theName);//类Animal的构造器 
    void eat();
    void sleep();
    void drool();//流鼻涕
};
Animal::Animal(std::string theName)//类Animal构造器函数 
{
    name = theName;
}

class Pig:public Animal//类Pig继承于类Animal
{
public:
    Pig(std::string theName);//类Pig的构造器
    void climb();
};
Pig::Pig(std::string theName):Animal(theName)//类Pig的构造函数继承于类Animal的构造函数 
{
    
}

class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    Turtle(std::string theName);//类Pig的构造器
    void swim();
};
Turtle::Turtle(std::string theName):Animal(theName)//类Turtle的构造函数继承于类Animal的构造函数参数 
{
    
}

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}
void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}

void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}
int main()
{
    Pig pig(“小猪猪”);//定义一个对象pig,由于其继承于类Animal,
    //且构造函数也继承于类Animal的构造函数,所以参数"小猪猪"将赋值给类pig中的名字属性name 
    Turtle turtle(“小甲鱼”);//定义一个对象turtle
    
    std::cout << “这只猪的名字是:” << pig.name << std::endl;
    std::cout << “每只乌龟都有个伟大的名字:” << turtle.name << std::endl;

pig.eat();
    turtle.eat();
    pig.climb();
    turtle.swim();

return 0;
}

实例2:构造器与析构器的综合运用

#include
#include
//由于继承,编译后将首先调用基类构造器,然后调用子类构造器,然后运行其它程序;
//运行到程序末尾时,先调用子类析构器,让后调用基类析构器。
class BaseClass//定义基类BaseClass 
{
public:
    BaseClass();//构造器
    ~BaseClass();//析构器
    
    void doSomething();    
};

class SubClass : public BaseClass定义子类SubClass,类SubClass继承于类BaseClass 
{
public:
    SubClass();
    ~SubClass();
};

BaseClass::BaseClass()//类BaseClass构造器函数 
{
    std::cout << “进入基类构造器。。。\n”;
    std::cout << “我在基类构造器里边干了某些事。。。\n\n”;
}

BaseClass::~BaseClass()//类BaseClass析构器函数 
{
    std::cout << “进入基类析构器。。。\n”;
    std::cout << “我在基类析构器里边干了某些事。。。\n\n”;
}
void BaseClass::doSomething()//基类的doSomething函数 
{
    std::cout << “我干了某些事。。。\n\n”;

SubClass::SubClass()//子类SubClass的构造函数 
{
    std::cout << “进入子类构造器。。。\n”;
    std::cout << “我在子类构造器里面还干了某些事。。。\n\n”;
}
SubClass::~SubClass()//子类SubClass的析构函数 
{
    std::cout << “进入子类析构器。。。\n”;
    std::cout << “我在子类析构器里面还干了某些事。。。\n\n”;
}
int main()
{
    SubClass subclass;
    subclass.doSomething();
    
    std::cout << “完事,收工!\n”; 
    return 0;
}

第十八讲:访问控制

访问控制:C++提供用来保护(保护意思是对谁可以调用某个方法和访问某一个属性加上一个限制)类里的方法和属性的手段

实例1:访问级别应用

//级别            允许谁来访问
//public           任何代码 
//protected        这个类本身和它的子类 
//private          只有这个类本身
#include
#include

class Animal//定义Animal类
{
public:
    std::string mouth;
    //std::string name;
    
    Animal(std::string theName);//类Animal的构造器 
    void eat();
    void sleep();
    void drool();//流鼻涕
protected:
    std::string name;
};
Animal::Animal(std::string theName)//类Animal构造器函数 
{
    name = theName;
}

class Pig:public Animal//类Pig继承于类Animal
{
public:
    Pig(std::string theName);//类Pig的构造器
    void climb();
};
Pig::Pig(std::string theName):Animal(theName)//类Pig的构造函数继承于类Animal的构造函数 
{
    
}

class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    Turtle(std::string theName);//类Pig的构造器
    void swim();
};
Turtle::Turtle(std::string theName):Animal(theName)//类Turtle的构造函数继承于类Animal的构造函数参数 
{
    
}

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}
void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}

void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}
int main()
{
    Pig pig(“小猪猪”);//定义一个对象pig,由于其继承于类Animal,
    //且构造函数也继承于类Animal的构造函数,所以参数"小猪猪"将赋值给类pig中的名字属性name 
    Turtle turtle(“小甲鱼”);//定义一个对象turtle
    
    //pig.name = “小甲鱼”; //由于name被保护起来,所以赋值将报错 
    
    std::cout << “这只猪的名字是:” << pig.name << std::endl;
    std::cout << “每只乌龟都有个伟大的名字:” << turtle.name << std::endl;

pig.eat();
    turtle.eat();
    pig.climb();
    turtle.swim();

return 0;
}

使用private的好处:可以只修改某个类的内部实现,而不必重新修改整个程序。因为其他代码根本就访问不到private保护的内容

在同一个类中可以使用多个public:,private和protected:语句,但最好把你的元素集中到一个地方,可读性会更好。

protected

把基类的访问级别改为protected,如果原来是public的话。这将使得这个子类外部的代码无法通过子类去访问基类中的public

private

是在告诉编译器从基类继承来的每一个成员都当做private来对待,这意味着只有这个子类可以使用它从基类继承来的元素。

第十九讲:覆盖方法和重载方法

覆盖是指派生类函数覆盖基类函数(函数名字参数相同且基类函数必须有virtual关键字)

以上学习可知可以通过创建新的子类来重用现有的代码(继承)

当我们需要在基类里提供一个通用的函数,但在它的某个子类里需要修改这个方法的实现,覆盖(overriding)就可以做到。

实例1:覆盖应用

//级别            允许谁来访问
//public           任何代码 
//protected        这个类本身和它的子类 
//private          只有这个类本身
#include
#include

class Animal//定义Animal类
{
public:
    std::string mouth;
    //std::string name;
    
    Animal(std::string theName);//类Animal的构造器 
    void eat();
    void sleep();
    void drool();//流鼻涕
protected:
    std::string name;
};
Animal::Animal(std::string theName)//类Animal构造器函数 
{
    name = theName;
}

class Pig:public Animal//类Pig继承于类Animal
{
public:
    Pig(std::string theName);//类Pig的构造器
    void climb();
    void eat();   //new  再一次声明,以便原函数可以覆盖修改 
};
Pig::Pig(std::string theName):Animal(theName)//类Pig的构造函数继承于类Animal的构造函数 
{
    
}

class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    Turtle(std::string theName);//类Pig的构造器
    void swim();
    void eat();   //new  再一次声明,以便原函数可以覆盖修改 
};
Turtle::Turtle(std::string theName):Animal(theName)//类Turtle的构造函数继承于类Animal的构造函数参数 
{
    
}

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}
void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}

void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}
void Pig::eat()//重新声明eat方法 
{
    Animal::eat();//可省去 
    std::cout << “我在吃鱼\n\n” << std::endl;
}
void Turtle::eat()//重新声明eat方法 
{
    Animal::eat();//可省去
    std::cout << “我正在吃东坡肉!\n\n” << std::endl;
}

int main()
{
    Pig pig(“小猪猪”);//定义一个对象pig,由于其继承于类Animal,
    //且构造函数也继承于类Animal的构造函数,所以参数"小猪猪"将赋值给类pig中的名字属性name 
    Turtle turtle(“小甲鱼”);//定义一个对象turtle
    
    //pig.name = “小甲鱼”; //由于name被保护起来,所以赋值将报错 
    
//  std::cout << “这只猪的名字是:” << pig.name << std::endl;        
//    std::cout << “每只乌龟都有个伟大的名字:” << turtle.name << std::endl;

pig.eat();
    turtle.eat();
    pig.climb();
    turtle.swim();

return 0;
}

重载机制使你可以定义多个同名的方法(函数),只是它们的输入参数必须不同。(因为编译器是依靠不同的输入参数来区分不同的方法)

实例2:重载应用

//级别            允许谁来访问
//public           任何代码 
//protected        这个类本身和它的子类 
//private          只有这个类本身
#include
#include

class Animal//定义Animal类
{
public:
    std::string mouth;
    //std::string name;
    
    Animal(std::string theName);//类Animal的构造器 
    void eat();
    void eat(int eatCount); 
    void sleep();
    void drool();//流鼻涕
protected:
    std::string name;
};
Animal::Animal(std::string theName)//类Animal构造器函数 
{
    name = theName;
}

class Pig:public Animal//类Pig继承于类Animal
{
public:
    Pig(std::string theName);//类Pig的构造器
    void climb();
};
Pig::Pig(std::string theName):Animal(theName)//类Pig的构造函数继承于类Animal的构造函数 
{
    
}

class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    Turtle(std::string theName);//类Pig的构造器
    void swim();
};
Turtle::Turtle(std::string theName):Animal(theName)//类Turtle的构造函数继承于类Animal的构造函数参数 
{
    
}

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}
void Animal::eat(int eatCount)
{
    std::cout << “我吃了” << eatCount << “碗馄饨!\n”;
}
void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}

void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}

int main()
{
    Pig pig(“小猪猪”);//定义一个对象pig,由于其继承于类Animal,
    //且构造函数也继承于类Animal的构造函数,所以参数"小猪猪"将赋值给类pig中的名字属性name 
    Turtle turtle(“小甲鱼”);//定义一个对象turtle
    
    //pig.name = “小甲鱼”; //由于name被保护起来,所以赋值将报错 
//  std::cout << “这只猪的名字是:” << pig.name << std::endl;        
//    std::cout << “每只乌龟都有个伟大的名字:” << turtle.name << std::endl;

pig.eat();
    turtle.eat();
    
    pig.eat(15);
    pig.climb();
    turtle.swim();

return 0;
}
在对方法进行覆盖(注意区分覆盖和重载)时,一定要看仔细,因为只要声明的输入参数和返回值与原来的不一致,你编写出来的就将是一个重载的方法而不是覆盖方法。

实例3:子类内声明重载

//级别            允许谁来访问
//public           任何代码 
//protected        这个类本身和它的子类 
//private          只有这个类本身
#include
#include

class Animal//定义Animal类,基类 
{
public:
    std::string mouth;
    //std::string name;
    
    Animal(std::string theName);//类Animal的构造器 
    void eat();
    
    void sleep();
    void drool();//流鼻涕
protected:
    std::string name;
};
Animal::Animal(std::string theName)//类Animal构造器函数 
{
    name = theName;
}

class Pig:public Animal//类Pig继承于类Animal,子类 
{
public:
    Pig(std::string theName);//类Pig的构造器
    void climb();
    void eat(int eatCount);//重载 
};
Pig::Pig(std::string theName):Animal(theName)//类Pig的构造函数继承于类Animal的构造函数 
{
    
}

class Turtle:public Animal//类Turtle继承于类Animal
{
public:
    Turtle(std::string theName);//类Pig的构造器
    void swim();
};
Turtle::Turtle(std::string theName):Animal(theName)//类Turtle的构造函数继承于类Animal的构造函数参数 
{
    
}

void Animal::eat()//Animal类中的方法函数
{
    std::cout << “I’m eatting!” << std::endl;
}

void Animal::sleep()
{
    std::cout << “I’m sleeping!Don’t disturb me!” << std::endl;
}
void Animal::drool()
{
    std::cout << “我是公的,看到母的会流口水 流口水。。。” << std::endl;
}

void Pig::climb()//类Pig中的climb方法函数
{
    std::cout << “我是一只漂亮的小母猪猪,我会上树,邱。。。” << std::endl;
}
void Pig::eat(int eatCount)
{
    std::cout << “我吃了” << eatCount << “碗馄饨!\n”;
}

void Turtle::swim()//类Turtle中的swim方法函数
{
    std::cout << “我是一只小甲鱼,当母猪抓我,我就游到海里,哈。。。” << std::endl;
}

int main()
{
    Pig pig(“小猪猪”);//定义一个对象pig,由于其继承于类Animal,
    //且构造函数也继承于类Animal的构造函数,所以参数"小猪猪"将赋值给类pig中的名字属性name 
    Turtle turtle(“小甲鱼”);//定义一个对象turtle
    
    //pig.name = “小甲鱼”; //由于name被保护起来,所以赋值将报错 
//  std::cout << “这只猪的名字是:” << pig.name << std::endl;        
//    std::cout << “每只乌龟都有个伟大的名字:” << turtle.name << std::endl;

//pig.eat();   由于eat在子类中被重载,所以不能再被调用;如果在基类重载则可以调用 
    turtle.eat();
    
    pig.eat(15);//重载函数 
    pig.climb();
    turtle.swim();

return 0;
}

第二十讲:一种特殊的友情关系——友元关系

友元关系是类之间的一种特殊关系,这种关系不仅允许友元类访问对方的public方法和属性,还允许友元访问对方的protected和private方法和属性。

实例1:友元关系访问保护量

#include
#include

using namespace std;
class Lovers//爱人关系,基类 
{
public:
    Lovers(string theName);//
    void kiss(Lovers *lover);
    void ask(Lovers *lover, string something);
    
protected:
    string name;
    
    friend class Others; //祸根,交友不慎。。。。 (友元关系),则Others可以访问name 
};

class Boyfriend:public Lovers//Boyfriend子类,继承Lovers基类 
{
public:
    Boyfriend(string theName);
};
class Girlfriend:public Lovers//girlfriend子类,继承Lovers基类 
{
public:
    Girlfriend(string theName);
};

class Others//Others类 ,并没继承Lovers基类 
{
public:
    Others(string theName);
    void kiss(Lovers *lover);
    
protected:
    string name;
};

Lovers::Lovers(string theName)//Lovers类的构造函数 
{
    name = theName;
}
void Lovers::kiss(Lovers *lover)//Lovers *lover表示定义Lovers类的一个对象*lover 
{
    cout << name << “亲亲我们家的” << lover->name << endl;

void Lovers::ask(Lovers *lover,string something)
{
    cout << “宝贝儿” << lover->name << “帮我” << something << endl;
}
Boyfriend::Boyfriend(string theName):Lovers(theName)
{
}
Girlfriend::Girlfriend(string theName):Lovers(theName)
{
}
Others::Others(string theName)
{
    name = theName;
}
void Others::kiss(Lovers *lover)
{
    cout << name << “亲一下” << lover->name << endl;
}
int main()
{
    Boyfriend boyfriend(“A君”);
    Girlfriend girlfriend(“B妞”);
    
    Others others(“路人甲”);
    
    girlfriend.kiss(&boyfriend);
    girlfriend.ask(&boyfriend,“洗衣服啦”);
    
    cout << “\n当当当当!传说中的路人甲登场啦。。。。\n”;
    others.kiss(&girlfriend);
    
    return 0; 
}

第二十一讲:静态属性和静态方法

面对对象编程技术的一个重要特征是用一个对象把数据和对数据处理的方法封装在一起。

在前面的例子里,我们一直是在使用对象(也可以说某个类的实例)来调用方法,每个方法只处理调用它的那个对象所包含的数据,所有的数据都属于同一个对象。

C++允许我们把一个或多个成员声明为属于某个类,而不是仅属于该类的对象。(就是说这个类仅能让该类强暴)。好处是,程序员可以在没有创建任何对象的情况下调用有关的方法。另一个好处是能够让有关的数据仍在该类的所有对象间共享。

实例1:静态变量实例

#include
#include

using namespace std;
class Pet//定义Pet类 
{
public:
    Pet(string theName);//构造器,对count进行写操作 
    ~Pet();//析构器,对count进行写操作  
    
    static int getCount();//定义静态函数,对count进行读操作 
    
protected://不允许没有继承Pet类的其它类调用 
    string name;
private://定义的变量和函数只服务于Pet类中的函数
    static int count;//定义静态变量(属性) 
};
int Pet::count = 0;//注意这一句,他起码做了两件事(为count分配静态内存,初始化为0) 
Pet::Pet(string theName)//构造函数 
{
    name = theName;
    count++;
    
    cout << “一只宠物出生了,名字叫做:” << name << “\n”; 

 Pet::~Pet()//析构函数 
 {
     count–;
     cout << “\n” << name << “挂掉了\n”;
  } 
int Pet::getCount()//返回count值 
{
    return count;
}

class Dog:public Pet//定义Dog类继承于Pet类 
{
public:
    Dog(string theName);
};
Dog::Dog(string theName):Pet(theName)//Dog的构造函数继承于Pet类中的Pet(theName)函数,即该构造函数调用时将调用Pet函数 
{
}

class Cat:public Pet//定义Cat类继承于Pet类 
{
public:
    Cat(string theName);
};
Cat::Cat(string theName):Pet(theName)//Cat的构造函数继承于Pet类中的Pet(theName)函数
{
}

int main()
{
    Dog dog(“Tom”);
    Cat cat(“Jerry”);
    
    cout << “\n已经诞生了” << Pet::getCount()  << “只宠物!\n\n”;
    //如果有括号的话,编译器是在括号结束时调用dog_2与cat_2的析构函数,而没有的话,则是程序结尾处调用析构函数 
//    {
        Dog dog_2(“Tom_2”);
        Cat cat_2(“Jerry_2”);
        
        cout << “\n现在呢,已经诞生了” << Pet::getCount() << “只宠物!”;
//    }
    cout << “\n现在还剩下” << Pet::getCount() << “只宠物!”;
    
    return 0;
}

第二十二讲:静态属性和静态方法2

规则:

静态成员是所有对象共享的,所以不能在静态方法里访问非静态的元素。(因为每个对象都有自己的this指针,静态方法不是属于某个特定的对象,而是由全体对象共享的,静态成员存储地址与对象并不在一起)

非静态方法可以访问类的静态成员,也可以访问类的非静态成员。

this指针是类的一个自动生成、自动隐藏的私有成员,它存在于类的非静态成员函数中,指向被调用函数所在的对象的地址。

当一个对象被创建时,该对象的this指针就自动指向对象数据的首地址。

当我们调用一个方法时,this指针都会随着你提供的输入参数被秘密的传递给那个方法。

实例1:this指针应用

#include
#include

using namespace std;
class Pet//定义Pet类 
{
public:
    Pet(string theName);//构造器,对count进行写操作 
    ~Pet();//析构器,对count进行写操作  
    
    static int getCount();//定义静态函数,对count进行读操作 
    
protected://不允许没有继承Pet类的其它类调用 
    string name;
private://定义的变量和函数只服务于Pet类中的函数
    static int count;//定义静态变量(属性) 
};
int Pet::count = 0;//注意这一句,他起码做了两件事(为count分配静态内存,初始化为0) 外部对静态属性进行声明 
Pet::Pet(string theName)//构造函数 
{
    name = theName;
    count++;
    
    cout << “一只宠物出生了,名字叫做:” << name << “\n”; 

 Pet::~Pet()//析构函数 
 {
     count–;
     cout << “\n” << name << “挂掉了\n”;
  } 
int Pet::getCount()//返回count值 
{
    return count;
}

class Dog:public Pet//定义Dog类继承于Pet类 
{
public:
    Dog(string theName);
};
Dog::Dog(string theName):Pet(theName)//Dog的构造函数继承于Pet类中的Pet(theName)函数,即该构造函数调用时将调用Pet函数 
{
    cout << “this:” << this << “\n”;//打印this指针地址 
}

class Cat:public Pet//定义Cat类继承于Pet类 
{
public:
    Cat(string theName);
};
Cat::Cat(string theName):Pet(theName)//Cat的构造函数继承于Pet类中的Pet(theName)函数
{
}

int main()
{
    Dog dog(“Tom”);
    Cat cat(“Jerry”);
    
    cout << “dog:” << &dog << “\n”;//打印指向dog对象的this指针地址 
    cout << “\n已经诞生了” << Pet::getCount()  << “只宠物!\n\n”;
    //如果有括号的话,编译器是在括号结束时调用dog_2与cat_2的析构函数,而没有的话,则是程序结尾处调用析构函数 
//    {
        Dog dog_2(“Tom_2”);
        Cat cat_2(“Jerry_2”);
        
        cout << “\n现在呢,已经诞生了” << Pet::getCount() << “只宠物!”;
//    }
    cout << “\n现在还剩下” << Pet::getCount() << “只宠物!”;
    
    return 0;
}

第二十三讲:虚方法

TIPS:

引发问题的源头是我们使用了new在程序运行的时候才为dog和cat分配Dog类型和Cat类型的指针。这些都是它们在运行时才分配的类型,和它们在编译时的类型是不一样的。

如果拿不准要不要把某种方法声明为虚方法,那么就把它声明为虚方法好了。

在基类里把所有的方法都声明为虚方法会让最终的可执行代码的速度变得稍微慢一些,但好处是可以一劳永逸地确保程序的行为符合你的预期。

实例:虚方法的运用

//int *pointer = new int;//声明一个整型指针,并在程序运行时将它指向分配的内存空间 
//delect *pointer;//删除指针,释放内存 
#include
#include

using namespace std;

class Pet//定义Pet类 
{
public:
    Pet(string theName);//构造器,对count进行写操作 
    
    void eat();
    void sleep();
    virtual void play();//定义虚方法play,将在编译时为其分配内存 
    
protected://不允许没有继承Pet类的其它类调用 
    string name;
};
Pet::Pet(string theName)
{
    name = theName;
}
void Pet::eat()
{
    cout << name << “正在吃东西!\n”;
}
void Pet::sleep()
{
    cout << name << “正在睡大觉!\n”;
}
void Pet::play()
{
    cout << name << “正在玩儿!\n”;
}

class Cat:public Pet//定义Cat类继承于Pet类 
{
public:
    Cat(string theName);//构造器
    
    void climb();
    void play();
};
Cat::Cat(string theName):Pet(theName)//Cat的构造函数继承于Pet类中的Pet(theName)函数
{
}
void Cat::climb()
{
    cout << name << “正在爬树!\n”;
}
void Cat::play()
{
    cout << name << “玩毛绒球!\n”;
}

class Dog:public Pet//定义Dog类继承于Pet类 
{
public:
    Dog(string theName);//构造器
    
    void bark();
    void play();
};
Dog::Dog(string theName):Pet(theName)//Dog的构造函数继承于Pet类中的Pet(theName)函数
{
}
void Dog::bark()
{
    cout << name << “汪汪汪!\n”;
}
void Dog::play()
{
    Pet::play();
    cout << name << “正在追赶那只该死的猫!\n”;
}
int main()
{
    Pet *cat = new Cat(“加菲”);
    Pet *dog = new Dog(“欧迪”);
    
    cat -> sleep();
    cat -> eat();
    cat -> play();
    
    dog -> sleep();
    dog -> eat();
    dog -> play();
    
    delete cat;
    delete dog;
    
    return 0;
 }

第二十四讲:抽象方法抽象方法(abstract method,也可以成为纯虚函数)

实例1:抽象方法应用

//int *pointer = new int;//声明一个整型指针,并在程序运行时将它指向分配的内存空间 
//delect *pointer;//删除指针,释放内存 
#include
#include

using namespace std;

class Pet//定义Pet类 
{
public:
    Pet(string theName);//构造器,对count进行写操作 
    
    virtual void eat();
    virtual void sleep();
    virtual void play() = 0;//定义抽象方法play,具体只需在继承类中声明实现即可,基类中不需要具体实现 
    
protected://不允许没有继承Pet类的其它类调用 
    string name;
};
Pet::Pet(string theName)
{
    name = theName;
}
void Pet::eat()
{
    cout << name << “正在吃东西!\n”;
}
void Pet::sleep()
{
    cout << name << “正在睡大觉!\n”;
}

class Cat:public Pet//定义Cat类继承于Pet类 
{
public:
    Cat(string theName);//构造器
    
    void climb();
    void play();
};
Cat::Cat(string theName):Pet(theName)//Cat的构造函数继承于Pet类中的Pet(theName)函数
{
}
void Cat::climb()
{
    cout << name << “正在爬树!\n”;
}
void Cat::play()
{
    cout << name << “玩毛绒球!\n”;
}

class Dog:public Pet//定义Dog类继承于Pet类 
{
public:
    Dog(string theName);//构造器
    
    void bark();
    void play();
};
Dog::Dog(string theName):Pet(theName)//Dog的构造函数继承于Pet类中的Pet(theName)函数
{
}
void Dog::bark()
{
    cout << name << “汪汪汪!\n”;
}
void Dog::play()
{
    //Pet::play();
    cout << name << “正在追赶那只该死的猫!\n”;
}
int main()
{
    Pet *cat = new Cat(“加菲”);
    Pet *dog = new Dog(“欧迪”);
    
    cat -> sleep();
    cat -> eat();
    cat -> play();
    
    dog -> sleep();
    dog -> eat();
    dog -> play();
    
    delete cat;
    delete dog;
    
    return 0;
 }

多态性:是指用一个名字定义不同的函数,调用同一个名字的函数,却执行不同的操作,从而实现传说中的“一个接口,多种方法”。

一般类的析构函数都是释放内存资源,如果析构函数不被调用的话将会造成内存泄漏。

析构器定义为虚方法是为了当一个基类的指针删除一个派生类的对象时,派生类的析构函数可以被正确调用。

当类里面有虚函数时,编译器会给类添加一个虚函数表,里面存放着虚函数指针。为了节省资源,只有当一个类被用来作为基类时,我们才把析构函数写成虚函数。

实例2:析构函数解析

#include
//析构器都是虚方法 
using namespace std;

class ClxBase//定义基类ClxBase 
{
public:
    ClxBase()//构造器 
    {
        cout << “ClxBase begin!\n”;
    };
    virtual ~ClxBase()//析构器 ,如果其不为虚函数,则子类的析构函数将不被执行,将造成内存泄漏 
    {
        cout << “ClxBase end!\n”; 
    };
    virtual void doSomething()//定义抽象方法doSomething 具体只需在继承类中声明实现即可(便可覆盖基类中定义),基类中可以不具体实现 
    {
        cout << “Do something in class ClxBase!\n”; 
    }
};

class ClxDerived:public ClxBase//定义子类ClxDerived继承于基类ClxBase 
{
public:
    ClxDerived()//子类构造器 
    {
        cout << “ClxDerived begin!\n”;
    };
    ~ClxDerived()//子类析构器 
    {
        cout << “Output from the destructor of class ClxDerived!\n”;
    };
    void doSomething()
    {
        cout << “Do something in class ClxDerived!\n”;
    };
};

int main()
{
    ClxBase *pTest = new ClxDerived;//定义一个pTest指针指向继承于ClxBase的ClxDerived对象,并为此指针分配内存 
    pTest -> doSomething();
    
    delete pTest;
    
    return 0;
}

第二十五讲:运算符的重载

所谓重载,就是重新赋予新的含义,函数重载是对一个已有的函数赋予新的含义。

运算符重载的方法是定义一个重载运算符的函数,在需要执行被重载的运算符时,系统就自动调用该运算符。也就是说,运算符重载是通过定义函数实现的,运算符重载实质是是函数的重载。

实例1:复数加法

#include

using namespace std; 
class Complex//定义基类
{
public:
    Complex();//构造器 
    Complex(double r,double i);//重载函数,输入参数不同,功能不同 
    Complex Complex_add(Complex &d);//加入一个方法,实现复数加法,Complex指其类型 
    void print();
    
private:
    double real;
    double imag;
};

Complex::Complex()//构造函数实现 
{
    real = 0;
    imag = 0;

Complex::Complex(double r,double i)//重载函数实现 
{
    real = r;
    imag = i;
}

Complex Complex::Complex_add(Complex &d)//Complex &d为定义基类对象d(被加数) complex_add为基类Complex方法 
{                                       //第二个Complex为继承基类的加数对象 
    Complex c;//定义基类对象c           //第一个Complex为其类型 
    
    c.real = real + d.real;
    c.imag = imag + d.imag;
    
    return c;
}
void Complex::print()
{
    cout << “(” << real << ", " << imag << “i)\n”;
}

int main()
{
    Complex c1(3,4),c2(5,-10),c3;//定义三个对象c1、c2、c3及其重载函数参数值 
    c3 = c1.Complex_add(c2);
    
    cout << "c1 = ";
    c1.print();
    cout << "c2 = ";
    c2.print();
    cout << "c1 + c2 = ";
    c3.print();
    
    return 0;
}

实例2:复数加法2

#include

using namespace std;
class Complex//定义基类
{
public:
    Complex();//构造器 
    Complex(double r,double i);//重载函数,输入参数不同,功能不同 
    friend Complex operator+(Complex &c,Complex &d);//加入一个方法,实现复数加法,Complex指其类型 
    void print();
    
private:
    double real;
    double imag;
};

Complex::Complex()//构造函数实现 
{
    real = 0;
    imag = 0;

Complex::Complex(double r,double i)//重载函数实现 
{
    real = r;
    imag = i;

//注意:这里作为友元函数,不属于Complex,记得别写:: 
Complex operator+(Complex &c,Complex &d)//Complex &d为定义基类对象d(被加数) complex_add为基类Complex方法 
{
    return Complex(c.real + d.real,c.imag + d.imag);
}
void Complex::print()
{
    cout << “(” << real << ", " << imag << “i)\n”;
}

int main()
{
    Complex c1(3,4),c2(5,-10),c3;//定义三个对象c1、c2、c3及其重载函数参数值 
    c3 = operator+(c1,c2);
    
    cout << "c1 = ";
    c1.print();
    cout << "c2 = ";
    c2.print();
    cout << "c1 + c2 = ";
    c3.print();
    
    return 0;
}

作业:分数加减乘除的操作符重载

#include
#include
#include <math.h>

using namespace std;
class Rational//定义基类
{
public:
    Rational(int num,int denom); //构造器 num = 分子,denom = 分母 
    
    Rational operator+(Rational rhs);// rhs == right hand side(右手边参数) 
    Rational operator-(Rational rhs);
    Rational operator*(Rational rhs);
    Rational operator/(Rational rhs);
    
    void print();//打印 
    
private:
    void normalize();//负责对分数的简化处理
    
    int numerator; //分子
    int denominator; //分母 
};

Rational::Rational(int num,int denom)//构造函数实现 
{
    numerator = num;
    denominator = denom;
    
    normalize(); 

//normalize()对分数进行简化操作包括:
//1.只允许分子为负数,如果分母为负数则把负数挪到分子部分,如1/-2==-1/2 
//2.利用欧几里德算法(辗转求余原理)将分数进行简化:2/10 => 1/5

void Rational::normalize()
{
    //确保分母为正
    if( denominator < 0) 
    {
        numerator = -numerator;
        denominator = -denominator;
    }
    //欧几里德算法 
    int a = abs(numerator);
    int b = abs(denominator);
    
    //求出最大公约数
    while(b>0)
    {
        int t = a % b;//取余 
        a = b;
        b = t;
    }
     
     //分子、分母分别除以最大公约数得到最简化分数
     numerator /= a;
     denominator /= a; 
}
//a   c   a*d   c*b   a*d + c*d
//- + - = — + — = ----------
//b   d   b*d   b*d      b*d
Rational Rational::operator+(Rational rhs)//分数的加运算 
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;
    
    int e = a*b + c*d;
    int f = b*d;
    
    return Rational(e,f);
}
//a   c   a   -c
//- - - = - + – 
//b   d   b   d 
Rational Rational::operator-(Rational rhs)//分数的减运算 
{
    rhs.numerator = -rhs.numerator; //被减数分子取负数 
    return operator+(rhs);
}
//a   c   a*c
//- * - = — 
//b   d   b*d 
Rational Rational::operator*(Rational rhs)//分数的乘运算
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;
    
    int e = a*c;
    int f = b*d;
    
    return Rational(e,f);
}
//a   c   a   d
//- / - = - * - 
//b   d   b   c
Rational Rational::operator/(Rational rhs)//分数的除运算
{
    //rhs的分子分母互换 
    int t = rhs.numerator;
    rhs.numerator = rhs.denominator;
    rhs.denominator = t;
    
    return operator*(rhs);
}
void Rational::print() //打印最简分数 
{
    if(numerator % denominator == 0)
    cout << numerator / denominator;
    else 
    cout << numerator << “/” << denominator;
}

int main()
{
    Rational f1(2,16);//定义f1对象,且传入(2,16)参数 
    Rational f2(7,8);
    
    //测试有理数加法运算 
    Rational res = f1 + f2;//相当于res=f1.operator+(f2)
    f1.print();
    cout << " + ";
    f2.print();
    cout << " = ";
    res.print();
    cout << “\n”; 
    
    //测试有理数减法运算 
    res = f1 - f2;
    f1.print();
    cout << " - ";
    f2.print();
    cout << " = ";
    res.print();
    cout << “\n”; 
    
    //测试有理数乘法运算 
    res = f1 * f2;
    f1.print();
    cout << " * ";
    f2.print();
    cout << " = ";
    res.print();
    cout << “\n”;
    
    //测试有理数除法运算 
    res = f1 / f2;
    f1.print();
    cout << " / ";
    f2.print();
    cout << " = ";
    res.print();
    cout << “\n”;
    
    return 0;
}

第二十六讲:运算符重载2

去重载一个操作符,应该只有在必要的时候,比如实现一种新的数据类型时,才重载操作符。

重载操作符的目的是为了让代码更容易阅读和理解。

第二十七讲:运算符左移<<重载

一般来说,在调用operator<<()重载函数时,传递给它的是哪一个流,它返回的就应该是那个流的一个引用。

实例:左移操作符重载

#include
#include
#include <math.h>

using namespace std;
class Rational//定义基类
{
public:
    Rational(int num,int denom); //构造器 num = 分子,denom = 分母 
    
    Rational operator+(Rational rhs);// rhs == right hand side(右手边参数) 
    Rational operator-(Rational rhs);
    Rational operator*(Rational rhs);
    Rational operator/(Rational rhs);
    
private:
    void normalize();//负责对分数的简化处理
    
    int numerator; //分子
    int denominator; //分母 
    
    friend ostream& operator<<(ostream& os,Rational f);//传递给它的是哪一个流,它返回的就是那个流的一个引用
};

Rational::Rational(int num,int denom)//构造函数实现 
{
    numerator = num;
    denominator = denom;
    
    normalize(); 

//normalize()对分数进行简化操作包括:
//1.只允许分子为负数,如果分母为负数则把负数挪到分子部分,如1/-2==-1/2 
//2.利用欧几里德算法(辗转求余原理)将分数进行简化:2/10 => 1/5

void Rational::normalize()
{
    //确保分母为正
    if( denominator < 0) 
    {
        numerator = -numerator;
        denominator = -denominator;
    }
    //欧几里德算法 
    int a = abs(numerator);
    int b = abs(denominator);
    
    //求出最大公约数
    while(b>0)
    {
        int t = a % b;//取余 
        a = b;
        b = t;
    }
     
     //分子、分母分别除以最大公约数得到最简化分数
     numerator /= a;
     denominator /= a; 
}
//a   c   a*d   c*b   a*d + c*d
//- + - = — + — = ----------
//b   d   b*d   b*d      b*d
Rational Rational::operator+(Rational rhs)//分数的加运算 
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;
    
    int e = a*b + c*d;
    int f = b*d;
    
    return Rational(e,f);
}
//a   c   a   -c
//- - - = - + – 
//b   d   b   d 
Rational Rational::operator-(Rational rhs)//分数的减运算 
{
    rhs.numerator = -rhs.numerator; //被减数分子取负数 
    return operator+(rhs);
}
//a   c   a*c
//- * - = — 
//b   d   b*d 
Rational Rational::operator*(Rational rhs)//分数的乘运算
{
    int a = numerator;
    int b = denominator;
    int c = rhs.numerator;
    int d = rhs.denominator;
    
    int e = a*c;
    int f = b*d;
    
    return Rational(e,f);
}
//a   c   a   d
//- / - = - * - 
//b   d   b   c
Rational Rational::operator/(Rational rhs)//分数的除运算
{
    //rhs的分子分母互换 
    int t = rhs.numerator;
    rhs.numerator = rhs.denominator;
    rhs.denominator = t;
    
    return operator*(rhs);
}

ostream& operator<<(ostream& os,Rational f);//函数声明

int main()
{
    Rational f1(2,16);//定义f1对象,且传入(2,16)参数 
    Rational f2(7,8);
    
    //测试有理数加法运算 
    cout << f1 << " + " << f2 << " == " << (f1+f2) << “\n”; // 左移操作符<<已经被重载了 
    
    //测试有理数减法运算 
     cout << f1 << " - " << f2 << " == " << (f1-f2) << “\n”; //<< f1中由于f1属于Rational类型,将自动转到打印分数形式输出 
    
    //测试有理数乘法运算 
     cout << f1 << " * " << f2 << " == " << (f1*f2) << “\n”;//<< "+"中由于<<后面参数是字符串,所以使用系统默认的打印 
    
    //测试有理数除法运算 
    cout << f1 << " / " << f2 << " == " << (f1/f2) << “\n”; 
    
    return 0;
}
ostream& operator<<(ostream& os,Rational f)//并不属于Rational类,是一个独立的函数 
{
    if(f.numerator % f.denominator == 0)
    os << f.numerator / f.denominator;
    else 
    os << f.numerator << “/” << f.denominator;//打印分数 
    return os; 
}

第二十八讲:多继承(multiple inheritance)

多继承语法:

//助教类既继承于老师类,又继承于学生类 
class Assistant:public Teacher,public Student
{
};

当遇到的问题无法只用一个“是一个”关系来描述的时候,就是多继承出场的时候。例即是学生,又是人,还是助教。

#include
#include

using namespace std;

#include
//人类 
class Person
{
public:
    Person(string theName);//构造函数,theName为类的输入参数 
    void introduce();
protected:
    string name;
};
Person::Person(string theName)//构造函数实现 
{
    name = theName;
}
void Person::introduce()//introduce()函数实现 
{
    cout << “大家好,我是” << name << “。\n\n”;
}

//老师类继承于人类 
class Teacher:public Person
{
public:
    Teacher(string theName,string theClass);
    
    void teach();//教书 
    void introduce();
protected:
    string classes;
};
Teacher::Teacher(string theName,string theClass):Person(theName)//老师的名字继承于人类中的名字 
{
    classes = theClass;
}
void Teacher::teach()
{
    cout<< name << " 教 "<< classes << “。\n\n”;
}
void Teacher::introduce()
{
    cout<<"大家好,我是 “<< name <<” ,我教 "<< classes << “。\n\n”;
}

//学生类继承于人类
class Student:public Person 
{
public:
    Student(string theName,string theClass);
    
    void attendClass();//要上课 
    void introduce();
protected:
    string classes;
};
Student::Student(string theName,string theClass):Person(theName)//学生名字继承于人类中的名字 
{
    classes = theClass;
}
void Student::attendClass()
{
    cout<< name <<“加入”<< classes << “学习。\n\n”;
}
void Student::introduce()
{
    cout<< “大家好,我是” << name << “,我在” << classes << “学习。\n\n”;
}

//助教类既继承于老师类,又继承于学生类 
class Assistant:public Teacher,public Student
{
public:
    Assistant(string theName,string classTeaching,string classAttending);
    
    void introduce();
};
Assistant::Assistant(string theName,string classTeaching,string classAttending):Teacher(theName, classTeaching),Student(theName,classAttending)
{

//多继承 助教既继承老师类,又继承学生类

}
void Assistant::introduce()
{
    cout << “大家好,我是” << Student::name << “.我教” << Teacher::classes << “,”;
    cout << “同时我在” << Student::classes << “学习。\n\n”; 
}

int main()
{
    Teacher teacher(“小甲鱼”,“C++入门班”);
    Student student(“迷途羔羊”,“C++入门班”);
    Assistant assistant(“丁丁”,“C++入门班”,“C++进阶班”);
    
    teacher.introduce();
    teacher.teach();
    
    student.introduce();
    student.attendClass();
    
    assistant.introduce();
    assistant.teach();
    assistant.attendClass();
    
    return 0;
}

第二十九讲:虚继承

通过虚继承某个基类,就是在告诉编译器:从当前这个类再派生出来的子类只能拥有那个基类的一个实例。

虚继承的语法:

class Teacher:virtual public Person

{

}

这样做的话便可以让Student和Teacher类都虚继承自Person类,编译器将确保从Student和Teacher类再派生出来的子类只能拥有一份Person类的属性。

实例:虚继承应用

#include
#include  
//虚继承可以让Student和Teacher类都虚继承自Person类,
//编译器将确保从Student和Teacher类再派生出来的子类只能拥有一份Person类的属性。
using namespace std;

#include
//人类 
class Person
{
public:
    Person(string theName);//构造函数,theName为类的输入参数 
    void introduce();
protected:
    string name;
};
Person::Person(string theName)//构造函数实现 
{
    name = theName;
}
void Person::introduce()//introduce()函数实现 
{
    cout << “大家好,我是” << name << “。\n\n”;
}

//老师类继承于人类 
class Teacher:virtual public Person//虚继承,再有类继承Teacher类时,将只拥有一份Person类的属性。 
{
public:
    Teacher(string theName,string theClass);
    
    void teach();//教书 
    void introduce();
protected:
    string classes;
};
Teacher::Teacher(string theName,string theClass):Person(theName)//老师的名字继承于人类中的名字 
{
    classes = theClass;
}
void Teacher::teach()
{
    cout<< name << " 教 "<< classes << “。\n\n”;
}
void Teacher::introduce()
{
    cout<<"大家好,我是 “<< name <<” ,我教 "<< classes << “。\n\n”;
}

//学生类继承于人类
class Student:virtual public Person//虚继承,再有类继承Student类时,将只拥有一份Person类的属性 
{
public:
    Student(string theName,string theClass);
    
    void attendClass();//要上课 
    void introduce();
protected:
    string classes;
};
Student::Student(string theName,string theClass):Person(theName)//学生名字继承于人类中的名字 
{
    classes = theClass;
}
void Student::attendClass()
{
    cout<< name <<“加入”<< classes << “学习。\n\n”;
}
void Student::introduce()
{
    cout<< “大家好,我是” << name << “,我在” << classes << “学习。\n\n”;
}

//助教类既继承于老师类,又继承于学生类 
class Assistant:public Teacher,public Student
{
public:
    Assistant(string theName,string classTeaching,string classAttending);
    
    void introduce();
};
Assistant::Assistant(string theName,string classTeaching,string classAttending)
:Teacher(theName, classTeaching),Student(theName,classAttending),Person(theName)
//由于虚继承,Teacher和Student都不能拥有Person类中的属性和方法
//只能由Person类自己给出 
{
   //多继承 助教既继承老师类,又继承学生类 
}
void Assistant::introduce()
{
    cout << “大家好,我是” << Student::name << “.我教” << Teacher::classes << “,”;
    cout << “同时我在” << Student::classes << “学习。\n\n”; 
}

int main()
{
    Teacher teacher(“小甲鱼”,“C++入门班”);

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
img
img

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

udent(“迷途羔羊”,“C++入门班”);
    Assistant assistant(“丁丁”,“C++入门班”,“C++进阶班”);
    
    teacher.introduce();
    teacher.teach();
    
    student.introduce();
    student.attendClass();
    
    assistant.introduce();
    assistant.teach();
    assistant.attendClass();
    
    return 0;
}

第二十九讲:虚继承

通过虚继承某个基类,就是在告诉编译器:从当前这个类再派生出来的子类只能拥有那个基类的一个实例。

虚继承的语法:

class Teacher:virtual public Person

{

}

这样做的话便可以让Student和Teacher类都虚继承自Person类,编译器将确保从Student和Teacher类再派生出来的子类只能拥有一份Person类的属性。

实例:虚继承应用

#include
#include  
//虚继承可以让Student和Teacher类都虚继承自Person类,
//编译器将确保从Student和Teacher类再派生出来的子类只能拥有一份Person类的属性。
using namespace std;

#include
//人类 
class Person
{
public:
    Person(string theName);//构造函数,theName为类的输入参数 
    void introduce();
protected:
    string name;
};
Person::Person(string theName)//构造函数实现 
{
    name = theName;
}
void Person::introduce()//introduce()函数实现 
{
    cout << “大家好,我是” << name << “。\n\n”;
}

//老师类继承于人类 
class Teacher:virtual public Person//虚继承,再有类继承Teacher类时,将只拥有一份Person类的属性。 
{
public:
    Teacher(string theName,string theClass);
    
    void teach();//教书 
    void introduce();
protected:
    string classes;
};
Teacher::Teacher(string theName,string theClass):Person(theName)//老师的名字继承于人类中的名字 
{
    classes = theClass;
}
void Teacher::teach()
{
    cout<< name << " 教 "<< classes << “。\n\n”;
}
void Teacher::introduce()
{
    cout<<"大家好,我是 “<< name <<” ,我教 "<< classes << “。\n\n”;
}

//学生类继承于人类
class Student:virtual public Person//虚继承,再有类继承Student类时,将只拥有一份Person类的属性 
{
public:
    Student(string theName,string theClass);
    
    void attendClass();//要上课 
    void introduce();
protected:
    string classes;
};
Student::Student(string theName,string theClass):Person(theName)//学生名字继承于人类中的名字 
{
    classes = theClass;
}
void Student::attendClass()
{
    cout<< name <<“加入”<< classes << “学习。\n\n”;
}
void Student::introduce()
{
    cout<< “大家好,我是” << name << “,我在” << classes << “学习。\n\n”;
}

//助教类既继承于老师类,又继承于学生类 
class Assistant:public Teacher,public Student
{
public:
    Assistant(string theName,string classTeaching,string classAttending);
    
    void introduce();
};
Assistant::Assistant(string theName,string classTeaching,string classAttending)
:Teacher(theName, classTeaching),Student(theName,classAttending),Person(theName)
//由于虚继承,Teacher和Student都不能拥有Person类中的属性和方法
//只能由Person类自己给出 
{
   //多继承 助教既继承老师类,又继承学生类 
}
void Assistant::introduce()
{
    cout << “大家好,我是” << Student::name << “.我教” << Teacher::classes << “,”;
    cout << “同时我在” << Student::classes << “学习。\n\n”; 
}

int main()
{
    Teacher teacher(“小甲鱼”,“C++入门班”);

收集整理了一份《2024年最新物联网嵌入式全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升的朋友。
[外链图片转存中…(img-y4wQfAXI-1715663745691)]
[外链图片转存中…(img-NDwih5w2-1715663745692)]

如果你需要这些资料,可以戳这里获取

一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人

都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值