零基础学习C++系列课程(十一) 持续更新中

目录

项目十 智能婚恋交友系统

第1节 项目需求

第2节 项目精讲-世界观的颠覆:面向对象的思想

第3节 项目精讲-女娲定义“人类”:类的使用

第4节 项目精讲-女娲造“人”:对象的基本使用

第5节 项目精讲-“生而不同”之构造函数

构造函数的作用

构造函数的特点

构造函数的种类

默认构造函数

第6节 合成的默认构造函数

第7节 手动定义的默认构造函数

第8节 自定义的重载构造函数

第9节 拷贝构造函数

手动定义的拷贝构造函数

合成的拷贝构造函数

第10节 什么时候调用拷贝构造函数

第11节 赋值构造函数

第12节 项目精讲-“最后的晚餐”之析构函数

第13节 项目精讲-永不迷失的真爱:this指针

第14节 项目精讲-类文件的分离

第15节 项目精讲-“大众情人”:静态数据成员

第16节 项目精讲-“不能拥有的方法”:静态成员函数

第17节 项目精讲-永葆初心之常成员

const数据成员

const成员函数

第18节 项目精讲-建模的常用手段:组合与聚合

组合

聚合

第19节 项目实现

第20节 常见错误总结

Error1-const

Error2-vector

Error2-const

Error3-static

第21节 英语不是障碍:计算机英语加油站

第22节 职场修炼:要不要加入创业团队?

第23节 逼格提升:不懂Linux的程序员 不是真正的程序员

第24节 项目练习

项目练习1

项目练习2

项目练习3


项目十 智能婚恋交友系统

为看书困难的小伙伴推荐视频教程:百度网盘 提取码:r59a

第1节 项目需求

婚恋交友-相亲

零基础学习C++系列课程(十一) 持续更新中_第1张图片

问题: 效率低下,时间成本大。

解决方案: 自动婚恋交友系统。 成功案例:百合网。

项目目标: 使用面向对象思想,开发自动相亲系统的核心框架。

第2节 项目精讲-世界观的颠覆:面向对象的思想

面向过程: 什么是面向过程? 根据程序的执行过程,来设计软件的所有细节。

面向过程的缺点: 开发大型项目时,越来越难以把控,甚至失去控制。 后期维护、更新成本很大。

解决方案: 使用面向对象。

什么是面向对象? 不是面向对象,写代码:

零基础学习C++系列课程(十一) 持续更新中_第2张图片

面向对象是一种开发思想,一种全新的开发方式。

面向对象思想的重要性:

开发大型项目必备,是高级程序员的必备技能!

零基础学习C++系列课程(十一) 持续更新中_第3张图片

第3节 项目精讲-女娲定义“人类”:类的使用

面向对象编程,最重要的第一个概念:类

“人类”是一个抽象的概念,不是具体的某个人。 “类”,是看不见,摸不着的,是一个纯粹的概念. “类”,是一种特殊的“数据类型”,不是一个具体的数据。

注意:类, 和基本数据类型(char/int/short/long/long long/float/double)不同

类的构成:方法和数据

零基础学习C++系列课程(十一) 持续更新中_第4张图片

​类的设计

零基础学习C++系列课程(十一) 持续更新中_第5张图片

定义一个“人类”: Demo

#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human {
public:  //公有的,对外的
	void eat(); //方法, “成员函数”
	void sleep();
	void play();
	void work();

	string getName();
	int getAge();
	int getSalary();

private:
	string name;
	int age;
	int salary;
};

void Human::eat() {
	cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep() {
	cout << "我正在睡觉!" << endl; 
}

void Human::play() {
	cout << "我在唱歌! " << endl; 
}

void Human::work() {
	cout << "我在工作..." << endl;
}

string Human::getName() {
	return name;
}

int Human::getAge() {
	return age;
}

int Human::getSalary() {
	return salary;
}

int main(void) {
	Human  zhangshan;

	system("pause");
}

第4节 项目精讲-女娲造“人”:对象的基本使用

什么是对象?

对象,是一个特定“类”的具体实例。

对象和普通变量有什么区别?

一般地,一个对象,就是一个特殊的变量,但是有跟丰富的功能和用法。

什么时候使用对象?

对象的具体使用方法

方式1

Demo1

int main(void)
{
    Human h1; // 通过自定义的特殊数据类型“Human”类, 来创建一个“对象”

    // 合法使用
    h1.eat();
    h1.play();
    h1.sleep();

    // 非法使用
    // cout << "年龄" << h1.age << endl;  //直接访问私有成员,将无法通过编译

    //正确使用
    cout << "年龄" << h1.getAge() << endl; //暴露问题,年龄值是一个很大的负数

    system("pause");
}

总结:

  1. “.”的使用

  2. 调用方法时,方法名后需要带一对圆括号()

  3. 通过对象,只能调用这个对象的public方法

分析:

多个不同的对象都有自己的数据,彼此无关。

方式2

Demo2

int main(void)
{
    Human h1; // 通过自定义的特殊数据类型“Human”类, 来创建一个“对象”
    Human *p;

    p = &h1;

    // 合法使用
    p->eat();
    p->play();
    p->sleep();

    // 非法使用
    // cout << "年龄" << p->age << endl;  //直接访问私有成员,将无法通过编译

    //正确使用
    cout << "年龄" << p->getAge() << endl; //暴露问题,年龄值是一个很大的负数

    system("pause");
}

小结:

  1. -> 的使用(类似C语言的结构体用法)

第5节 项目精讲-“生而不同”之构造函数

千人千面的“兵马俑”

零基础学习C++系列课程(十一) 持续更新中_第6张图片

在构造(制造)每个兵马俑的时候,使用了不同的“参数”。

构造函数的作用

在创建一个新的对象时,自动调用的函数,用来进行“初始化”工作:对这个对象内部的数据成员进行初始化。

构造函数的特点

  1. 自动调用(在创建新对象时,自动调用)

  2. 构造函数的函数名,和类名相同

  3. 构造函数没有返回类型

  4. 可以有多个构造函数(即函数重载形式)

构造函数的种类

默认构造函数

自定义的构造函数

拷贝构造函数

赋值构造函数

默认构造函数

没有参数的构造函数,称为默认构造函数。

第6节 合成的默认构造函数

但没有手动定义默认构造函数时,编译器自动为这个类定义一个构造函数。

  1. 如果数据成员使用了“类内初始值”,就使用这个值来初始化数据成员。【C++11】

  2. 否则,就使用默认初始化(实际上,不做任何初始化)

实例:demo3

#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:         //公有的,对外的
    void eat(); //方法, “成员函数”
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();

private:
    string name;
    int age = 18;
    int salary;
};

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

int main(void)
{
    Human h1;                                   // 使用合成的默认初始化构造函数
    cout << "年龄: " << h1.getAge() << endl;    //使用了类内初始值
    cout << "薪资:" << h1.getSalary() << endl; //没有类内初始值

    system("pause");
    return 0;
}

​注意:

只要手动定义了任何一个构造函数,编译器就不会生成“合成的默认构造函数”一般情况下,都应该定义自己的构造函数,不要使用“合成的默认构造函数”

【仅当数据成员全部使用了“类内初始值”,才宜使用“合成的默认构造函数”】

第7节 手动定义的默认构造函数

常称为“默认构造函数”

实例:demo4

#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:         //公有的,对外的
    Human();    //手动定义的“默认构造函数”
    void eat(); //方法, “成员函数”
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

int main(void)
{
    Human h1; // 使用自定义的默认构造函数
    cout << "姓名:" << h1.getName() << endl;
    cout << "年龄: " << h1.getAge() << endl;
    cout << "薪资:" << h1.getSalary() << endl;

    system("pause");
    return 0;
}

说明:如果某数据成员使用类内初始值,同时又在构造函数中进行了初始化,那么以构造函数中的初始化为准。相 当于构造函数中的初始化,会覆盖对应的类内初始值。

第8节 自定义的重载构造函数

#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

int main(void)
{
    Human h1(25, 35000); // 使用自定义的默认构造函数

    cout << "姓名:" << h1.getName() << endl;
    cout << "年龄: " << h1.getAge() << endl;
    cout << "薪资:" << h1.getSalary() << endl;

    system("pause");
    return 0;
}

第9节 拷贝构造函数

手动定义的拷贝构造函数

Demo.

#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    Human(const Human &);

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";
}

Human::Human(const Human &man)
{
    cout << "调用自定义的拷贝构造函数" << endl;
    name = man.name;
    age = man.age;
    salary = man.salary;
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

int main(void)
{
    Human h1(25, 35000); // 使用自定义的默认构造函数
    Human h2(h1);        // 使用自定义的拷贝构造函数

    cout << "姓名:" << h2.getName() << endl;
    cout << "年龄: " << h2.getAge() << endl;
    cout << "薪资:" << h2.getSalary() << endl;

    system("pause");
    return 0;
}

合成的拷贝构造函数

Demo.

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    // Human(const Human&);  //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();
    void setAddr(const char *newAddr);
    const char *getAddr();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";

    addr = new char[64];
    strcpy_s(addr, 64, "China");
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

void Human::setAddr(const char *newAddr)
{
    if (!newAddr)
    {
        return;
    }

    strcpy_s(addr, 64, newAddr);
}

const char *Human::getAddr()
{
    return addr;
}

int main(void)
{
    Human h1(25, 35000); // 使用自定义的默认构造函数
    Human h2(h1);        // 使用自定义的拷贝构造函数

    cout << "h1 addr:" << h1.getAddr() << endl;
    cout << "h2 addr:" << h2.getAddr() << endl;

    h1.setAddr("长沙");

    cout << "h1 addr:" << h1.getAddr() << endl;
    cout << "h2 addr:" << h2.getAddr() << endl;

    system("pause");
    return 0;
}

说明:

合成的拷贝构造函数的缺点: 使用“浅拷贝”

解决方案:在自定义的拷贝构造函数中,使用‘深拷贝

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    Human(const Human &); //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();
    void setAddr(const char *newAddr);
    const char *getAddr();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";

    addr = new char[64];
    strcpy_s(addr, 64, "China");
}

Human::Human(const Human &man)
{
    cout << "调用自定义的拷贝构造函数" << endl;
    age = man.age; // this是一个特殊的指针,指向这个对象本身
    salary = man.salary;
    name = man.name;
    // 深度拷贝
    addr = new char[64];
    strcpy_s(addr, 64, man.addr);
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

void Human::setAddr(const char *newAddr)
{
    if (!newAddr)
    {
        return;
    }

    strcpy_s(addr, 64, newAddr);
}

const char *Human::getAddr()
{
    return addr;
}

int main(void)
{
    Human h1(25, 35000); // 使用自定义的默认构造函数
    Human h2(h1);        // 使用自定义的拷贝构造函数

    cout << "h1 addr:" << h1.getAddr() << endl;
    cout << "h2 addr:" << h2.getAddr() << endl;

    h1.setAddr("长沙");

    cout << "h1 addr:" << h1.getAddr() << endl;
    cout << "h2 addr:" << h2.getAddr() << endl;

    system("pause");
    return 0;
}

第10节 什么时候调用拷贝构造函数

  1. 调用函数时,实参是对象,形参不是引用类型 如果函数的形参是引用类型,就不会调用拷贝构造函数

  2. 函数的返回类型是类,而且不是引用类型

  3. 对象数组的初始化列表中,使用对象。

Demo

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    Human(const Human &); //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();
    void setAddr(const char *newAddr);
    const char *getAddr();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";

    addr = new char[64];
    strcpy_s(addr, 64, "China");
}

Human::Human(const Human &man)
{
    cout << "调用自定义的拷贝构造函数"
         << "参数:" << &man
         << " 本对象:" << this << endl;

    age = man.age; // this是一个特殊的指针,指向这个对象本身
    salary = man.salary;
    name = man.name;
    // 深度拷贝
    addr = new char[64];
    strcpy_s(addr, 64, man.addr);
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

void Human::setAddr(const char *newAddr)
{
    if (!newAddr)
    {
        return;
    }

    strcpy_s(addr, 64, newAddr);
}

const char *Human::getAddr()
{
    return addr;
}

void test(Human man)
{
    cout << man.getSalary() << endl;
}

void test2(Human &man)
{ //不会调用拷贝构造函数,此时没有没有构造新的对象
    cout << man.getSalary() << endl;
}

Human test3(Human &man)
{
    return man;
}

Human &test4(Human &man)
{
    return man;
}

int main(void)
{
    Human h1(25, 35000); // 调用默认构造函数
    Human h2(h1);        // 调用拷贝构造函数
    Human h3 = h1;       // 调用拷贝构造函数

    test(h1);             // 调用拷贝构造函数
    test2(h1);            // 不会调用拷贝构造函数
    test3(h1);            // 创建一个临时对象,接收test3函数的返回值,调用1次拷贝构造函数
    Human h4 = test3(h1); // 仅调用1次拷贝构造函数,返回的值直接作为h4的拷贝构造函数的参数
    test4(h1);            // 因为返回的是引用类型,所以不会创建临时对象,不会调用拷贝构造函数

    Human men[] = {h1, h2, h3}; //调用3次拷贝构造函数

    system("pause");
    return 0;
}

第11节 赋值构造函数

Demo

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    Human(const Human &); //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
    Human &operator=(const Human &);

    void eat();
    void sleep();
    void play();
    void work();

    string getName();
    int getAge();
    int getSalary();
    void setAddr(const char *newAddr);
    const char *getAddr();

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;
}

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";

    addr = new char[64];
    strcpy_s(addr, 64, "China");
}

Human::Human(const Human &man)
{
    cout << "调用自定义的拷贝构造函数"
         << "参数:" << &man
         << " 本对象:" << this << endl;

    age = man.age; // this是一个特殊的指针,指向这个对象本身
    salary = man.salary;
    name = man.name;
    // 深度拷贝
    addr = new char[64];
    strcpy_s(addr, 64, man.addr);
}

Human &Human::operator=(const Human &man)
{
    cout << "调用" << __FUNCTION__ << endl;
    if (this == &man)
    {
        return *this; //检测是不是对自己赋值:比如 h1 = h1;
    }

    // 如果有必要,需要先释放自己的资源(动态内存)
    // delete addr;
    // addr = new char[ADDR_LEN];

    // 深拷贝
    strcpy_s(addr, ADDR_LEN, other.addr);

    // 处理其他数据成员
    name = man.name;
    age = man.age;
    salary = man.salary;

    // 返回该对象本身的引用, 以便做链式连续处理,比如 a = b = c;
    return *this;
}

void Human::eat()
{
    cout << "吃炸鸡,喝啤酒!" << endl;
}

void Human::sleep()
{
    cout << "我正在睡觉!" << endl;
}

void Human::play()
{
    cout << "我在唱歌! " << endl;
}

void Human::work()
{
    cout << "我在工作..." << endl;
}

string Human::getName()
{
    return name;
}

int Human::getAge()
{
    return age;
}

int Human::getSalary()
{
    return salary;
}

void Human::setAddr(const char *newAddr)
{
    if (!newAddr)
    {
        return;
    }

    strcpy_s(addr, 64, newAddr);
}

const char *Human::getAddr()
{
    return addr;
}

void test(Human man)
{
    cout << man.getSalary() << endl;
}

void test2(Human &man)
{ //不会调用拷贝构造函数,此时没有没有构造新的对象
    cout << man.getSalary() << endl;
}

Human test3(Human &man)
{
    return man;
}

Human &test4(Human &man)
{
    return man;
}

int main(void)
{
    Human h1(25, 35000); // 调用默认构造函数

    // 特别注意,此时是创建对象h2并进行初始化,调用的是拷贝构造函数,
    // 不会调用赋值构造函数
    Human h2 = h1;

    h2 = h1;        //调用赋值构造函数
    h2 = test3(h1); //调用赋值构造函数

    Human h3 = test3(h1); //调用拷贝构造函数

    system("pause");
    return 0;
}

如果没有定义赋值构造函数,编译器会自动定义“合成的赋值构造函数”,

与其他合成的构造函数,是“浅拷贝”(又称为“位拷贝”)。

第12节 项目精讲-“最后的晚餐”之析构函数

作用:对象销毁前,做清理工作。

具体的清理工作,一般和构造函数对应

比如:如果在构造函数中,使用new分配了内存,就需在析构函数中用delete释放。

如果构造函数中没有申请资源(主要是内存资源),

那么很少使用析构函数。

函数名:

~类型

没有返回值,没有参数,最多只能有一个析构函数

访问权限:

一般都使用public

使用方法:

不能主动调用。

对象销毁时,自动调用。

如果不定义,编译器会自动生成一个析构函数(什么也不做)

Demo

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    Human(const Human &); //不定义拷贝构造函数,编译器会生成“合成的拷贝构造函数”
    Human &operator=(const Human &);
    ~Human(); //析构函数
    ......

        private : string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

Human::Human()
{
    name = "无名氏";
    age = 18;
    salary = 30000;

    addr = new char[64];
    strcpy_s(addr, 64, "China");
    cout << "调用默认构造函数-" << this << endl;
}

......

    Human::~Human()
{
    cout << "调用析构函数-" << this << endl; //用于打印测试信息
    delete addr;
}

void test()
{
    Human h1;

    {
        Human h2;
    }
    cout << "test()结束" << endl;
}

int main(void)
{
    test();

    system("pause");
    return 0;
}

第13节 项目精讲-永不迷失的真爱:this指针

demo1

Human::Human(int age, int salary)
{
    cout << "调用自定义的构造函数" << endl;
    this->age = age; // this是一个特殊的指针,指向这个对象本身
    this->salary = salary;
    name = "无名";

    addr = new char[64];
    strcpy_s(addr, 64, "China");
}

说明:在类的静态成员函数【后续学习】中,不能使用this指针!

demo2

#include 
#include 
#include 
#include 

using namespace std;

// 定义一个“人类”
class Human
{
public:
    Human();
    Human(int age, int salary);
    ...... int getAge() const;
    const Human *compare1(const Human *);

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};

int Human::getAge() const
{
    return age;
}

const Human *Human::compare1(const Human *other)
{
    if (age > other->age)
    {
        return this; //没有创建新的对象
    }
    else
    {

        return other;
    }
}

int main(void)
{
    Human h1(25, 30000);
    Human h2(18, 8000);
    cout << h1.compare1(&h2)->getAge() << endl;

    system("pause");
    return 0;
}

demo3

class Human
{
public:
    Human();
    Human(int age, int salary);

    int getAge() const;

    const Human *compare1(const Human *);
    const Human &compare2(const Human &);

private:
    string name = "Unknown";
    int age = 28;
    int salary;
    char *addr;
};
const Human &Human::compare2(const Human &other)
{
    if (age > other.age)
    {
        return *this; //访问该对象本身的引用,而不是创建一个新的对象
    }
    else
    {

        return other;
    }
}

int main(void)
{
    Human h1(25, 30000);
    Human h2(18, 8000);
    cout << h1.compare2(h2).getAge() << endl;

    system("pause");
    return 0;
}

this不能指向其他对象,堪称“永不迷失的真爱”

class Human {
public:
	Human();
	Human(int age, int salary);
	......

	void thisTestError(Human *other) {
		this = other;  // 将报错!
	}
    ......
};

第14节 项目精讲-类文件的分离

实际开发中,类的定义保存在头文件中,比如Human.h【类的声明文件】(C++PrimerPlus)

类的成员函数的具体实现,保存在.cpp文件中,比如Human.cpp【类的方法文件】(C++PrimerPlus)

其他文件,如果需要使用这个类,就包含这个类的头文件。

第15节 项目精讲-“大众情人”:静态数据成员

需求分析:

需要获取总的人数,如何实现?

只能使用一个全局变量,然后在构造函数中对这个全局变量进行修改(加1)

缺点:使用全局变量不方便,破坏程序的封装性。

解决方案: 使用类的静态成员。

定义:

Human.h

class Human {
public:
	......
int getCount();
private:
	string name = "Unknown";
	int age = 28;
	......

	// 类的静态成员
	static int count;
};

初始化:

Human.cpp

#include "Human.h"	

// 初始化类的静态成员
int Human::count = 0;
......

Human::Human() {
	cout << "调用构造函数:" << this << endl;
	name = "无名氏";
	age = 18;
	salary = 30000;

	addr = new char[ADDR_LEN];
	strcpy_s(addr, ADDR_LEN, "China");

	count++;
}

// 类的普通成员函数,可以直接访问静态成员(可读可写)
int Human::getCount() {
	return count;
}

main.cpp

#include "Human.h"

int main(void) {
	Human h1;
	cout << h1.getCount() << endl;

	Human h2;
	cout << h1.getCount() << endl;

	system("pause");
	return 0;
}

对于非const的类静态成员,只能在类的实现文件中初始化。

const类静态成员,可以在类内设置初始值,也可以在类的实现文件中设置初始值。(但是不要同时在这两个地方初始化,只能初始化1次)

第16节 项目精讲-“不能拥有的方法”:静态成员函数

上一节getCount的讨论:

当需要获取总的人数时,还必须通过一个对象来访问,比如h1.getCount().

如果当前没有可用的对象时,就非常尴尬,不能访问getCount()!

void test() {
	cout << "总人数: ";
	// ??? 没有可用的对象来访问getCount()
}

如果为了访问总的人数,而特意去创建一个对象,就很不方便,

而且得到的总人数还不真实(包含了一个没有实际用处的人)

解决方案:

把getCount()方法定义为类的静态方法!

类的静态方法:

  1. 可以直接通过类来访问【更常用】,也可以通过对象(实例)来访问。

  2. 在类的静态方法中,不能访问普通数据成员和普通成员函数(对象的数据成员和成员函数)

Human.h

#pragma once
......
class Human {
public:
    ......
	static int getCount();
    ......
};

Human.cpp

......

//静态方法的实现,不能加static
int Human::getCount() { 
	//  静态方法中,不能访问实例成员(普通的数据成员)
	// cout << age;

	// 静态方法中,不能访问this指针
	// 因为this指针是属于实例对象的
	// cout << this;

	//静态方法中,只能访问静态数据成员
	return count;
}
......

main.cpp

void test() {
	cout << "总人数: ";
	// ??? 没有可用的对象来访问getCount()

	// 直接通过类名来访问静态方法!
	// 用法:类名::静态方法
	cout << Human::getCount(); 
}

int main(void) {
	Human h1, h2;

	test();

	system("pause");
	return 0;
}

说明:

零基础学习C++系列课程(十一) 持续更新中_第7张图片

  1. 静态数据成员 对象的成员函数(没有static的成员函数)内部,可以直接访问“静态数据成员” 类的静态成员函数(有static的成员函数)内部,可以直接访问“静态数据成员” 即:所有的成员函数,都可以访问静态数据成员。 类不能直接访问普通的静态数据成员(Human::humanCount 非法)

  2. 静态成员函数

        对象可以直接访问静态成员函数

        类可以直接访问静态成员函数(Human::getHumanCount())

        在类的静态成员函数(类的静态方法)内部,不能直接访问this指针和对象的数据成员!

        在类的静态成员函数(类的静态方法)内部,只能访问类的数据成员

第17节 项目精讲-永葆初心之常成员

const数据成员

需求分析:

怎样表示人的“血型”?

血型可以修改吗?

解决方案:

把血型定义为const数据类型(常量数据成员)

const数据成员的初始化方式:

  1. 使用类内值(C++11支持)

  2. 使用构造函数的初始化列表

(如果同时使用这两种方式,以初始化列表中的值为最终初始化结果)

注意: 不能在构造函数或其他成员函数内,对const成员赋值!

Demo

Human.h

#pragma once
......
class Human {
public:
    ......
private:
    ......
	const string bloodType;
};

Human.cpp

// 使用初始化列表,对const数据成员初始化
Human::Human():bloodType("未知") {
     ......

	//在成员函数内,不能对const数据成员赋值
	//bloodType = "未知血型";
	count++;
}

void Human::description() const {
	cout << "age:" << age
		<< " name:" << name
		<< " salary:" << salary
		<< " addr:" << addr 
		<< " bloodType:" << bloodType << endl; //其他成员函数可以“读”const变量
}

Main.cpp

int main(void) {
	Human h1;

	h1.description();

	system("pause");
	return 0;
}

const成员函数

需求分析:

const的Human对象,不能调用普通的成员函数。

分析:

C++认为,const(常量)对象,如果允许去调用普通的成员函数,而这个成员函数内部可能会修改这个对象的数据成员!而这讲导致const对象不再是const对象!

【类比】:专一男就是const对象,撩妹方法,就是普通的成员函数,如果允许专一男调去撩妹,那么专一男,也就不专一了!

解决方案:

如果一个成员函数内部,不会修改任何数据成员,就把它定义为const成员函数。

Human的description方法

//Human.h
class Human {
public:
    ......
	void description() const;  //注意,const的位置
    ......
};

//Human.cpp
void Human::description ()const {
	cout << "age:" << age
		<< " name:" << name
		<< " salary:" << salary
		<< " addr:" << addr 
		<< " bloodType:" << bloodType << endl;
}

//main.cpp
int main(void) {
	const Human h1;
	h1.description();
	
	system("pause");
	return 0;
}

const成员函数内,不能修改任何数据成员!

C++的成员函数设置建议:

如果一个对象的成员函数,不会修改任何数据成员,那么就强烈:

把这个成员函数,定义为const成员函数!

第18节 项目精讲-建模的常用手段:组合与聚合

说明:组合和聚合,不是C++的语法要求,是应用中的常用手段。

组合

需求: 构建一个计算机类,一台计算机,由CPU芯片,硬盘,内存等组成。

CPU芯片也使用类来表示。

【参考代码】P10-组合

CPU.h

#pragma once

#include 

class CPU
{
public:
	CPU(const char *brand = "intel", const char *version="i5");
	~CPU();
private:
	std::string brand; //品牌
	std::string version; //型号
};

CPU.cpp

#include "CPU.h"
#include 


CPU::CPU(const char *brand, const char *version)
{
	this->brand = brand;
	this->version = version;
	std::cout << __FUNCTION__ << std::endl;
}


CPU::~CPU()
{
	std::cout << __FUNCTION__ << std::endl;
}

Computer.h

#pragma once
#include "CPU.h"

class Computer
{
public:
	Computer(const char *cpuBrand, const char *cpuVersion, 
		int hardDisk, int memory);
	~Computer();
private:
	CPU cpu;      // Computer和CPU是“组合”关系
	int hardDisk; //硬盘, 单位:G
	int memory;   //内存, 单位:G
};

Computer.cpp

#include "Computer.h"
#include 


Computer::Computer(const char *cpuBrand, const char *cpuVersion,
	int hardDisk, int memory):cpu(cpuBrand, cpuVersion)
{
	this->hardDisk = hardDisk;
	this->memory = memory;

	std::cout << __FUNCTION__ << std::endl;
}


Computer::~Computer()
{
	std::cout << __FUNCTION__ << std::endl;
}

Main.cpp

include 
#include 
#include 
#include 
#include "Computer.h"

using namespace std;

void test() {
	Computer a("intel", "i9", 1000, 8);
}

int main(void) {
	test();

	system("pause");
	return 0;
}

小结:

被拥有的对象(芯片)的生命周期与其拥有者(计算机)的生命周期是一致的。

计算机被创建时,芯片也随之创建。

计算机被销毁时,芯片也随之销毁。

拥有者需要对被拥有者负责,是一种比较强的关系,是整体与部分的关系。

具体组合方式:

1)被组合的对象直接使用成员对象。(常用)

2)使用指针表示被组合的对象,在构造函数中,创建被组合的对象;在析构函数中,释放被组合的对象。

UML中的组合表示:

零基础学习C++系列课程(十一) 持续更新中_第8张图片

​注意包含者使用实心菱形

【补充】UML画图工具:starUML

聚合

需求: 给计算机配一台音响。

【参考代码】P10-聚合

Computer.h

#pragma once
#include "CPU.h"

class VoiceBox;

class Computer
{
public:
	Computer(const char *cpuBrand, const char *cpuVersion, 
		int hardDisk, int memory);
	~Computer();

	void addVoiceBox(VoiceBox *box);
private:
	CPU cpu;  // Computer和CPU是“组合”关系
	int hardDisk; //硬盘, 单位:G
	int memory;   //内存, 单位:G

	VoiceBox *box; //音箱
};

Computer.cpp

#include "Computer.h"
#include 
#include "VoiceBox.h"

Computer::Computer(const char *cpuBrand, const char *cpuVersion,
	int hardDisk, int memory):cpu(cpuBrand, cpuVersion)
{
	this->hardDisk = hardDisk;
	this->memory = memory;

	std::cout << __FUNCTION__ << std::endl;
}

void Computer::addVoiceBox(VoiceBox *box) {
	this->box = box;
}


Computer::~Computer()
{
	std::cout << __FUNCTION__ << std::endl;
}

Main.cpp

#include 
#include 
#include 
#include 
#include "Computer.h"
#include "VoiceBox.h"

using namespace std;

void test(VoiceBox *box) {
	Computer a("intel", "i9", 1000, 8);
	a.addVoiceBox(box);
}

int main(void) {
	VoiceBox box;

	test(&box);

	system("pause");
	return 0;
}

聚合不是组成关系,被包含的对象,也可能被其他对象包含。

拥有者,不需要对被拥有的对象的生命周期负责。

UML中的组合表示:

零基础学习C++系列课程(十一) 持续更新中_第9张图片

第19节 项目实现

回顾《项目需求》。

项目实现:

源码:P10-项目实现

Girl.h

#pragma once

#include 
#include 

using namespace std;

class Boy;

class Girl
{
public:
	Girl();
	Girl(int age, string name, int yanZhi);
	~Girl();

	int getAge()const;
	string getName()const;
	int getYanZhi()const;
	bool satisfied(const  Boy& s) const;
	string description()const;

	static void inputGirls(vector &girls);
private:
	int age;
	string name;
	int yanZhi;
};

Girl.cpp

#include "Girl.h"
#include "Boy.h"
#include 
#include 

#define YANZHI_FACTOR	100

Girl::Girl() {

}

Girl::Girl(int age, string name, int yanZhi) {
	this->age = age;
	this->name = name;
	this->yanZhi = yanZhi;
}

Girl::~Girl(){
}

int Girl::getAge() const {
	return age;
}

string Girl::getName() const {
	return name;
}

int Girl::getYanZhi()  const {
	return yanZhi;
}

bool Girl::satisfied(const Boy &s) const {
	if (s.getSalary() >= yanZhi * YANZHI_FACTOR) {
		return true;
	}
	else {
		return false;
	}
}

string Girl::description() const {
	stringstream ret;
	ret << name << "-女-颜值(" << yanZhi << ")-年龄(" << age << ")";
	return ret.str();
}

void Girl::inputGirls(vector &girls) {
	int age;
	string name;
	int yanZhi;
	int n = 1;

	while (1) {
		cout << "请输入第" << n << "位小姐姐的年龄【输入0结束】:";
		cin >> age;
		if (age == 0) {
			break;
		}

		cout << "请输入第" << n << "位小姐姐的姓名:";
		cin >> name;

		cout << "请输入第" << n << "位小姐姐的颜值:";
		cin >> yanZhi;

		n++;
		girls.push_back(Girl(age, name, yanZhi));
	}
}

Boy.h

#pragma once

#include 
#include 
using namespace std;

class Girl;

class Boy
{
public:
	Boy();
	Boy(int age, string name, int salary);
	~Boy();
	Boy(const Boy&other);
	int getAge()const;
	string getName()const;
	int getSalary()const;
	bool satisfied(const  Girl& s) const;
	string description() const;

	static void inputBoys(vector &boys);
private:
	int age;
	string name;
	int salary;
};

Boy.cpp

#include "Boy.h"
#include "Girl.h"
#include 
#include 

#define SALARY_FACTOR  0.006

Boy::Boy() {
}

Boy::Boy(const Boy&other) {
	salary = other.salary;
	name = other.name;
	age = other.age;
}

Boy::Boy(int age, string name, int salary) {
	this->age = age;
	this->name = name;
	this->salary = salary;
}

Boy::~Boy(){
}

int Boy::getAge() const {
	return age;
}

string Boy::getName() const {
	return name;
}

int Boy::getSalary()  const {
	return salary;
}

bool Boy::satisfied(const Girl &s) const {
	if (s.getYanZhi() >= salary * SALARY_FACTOR) {
		return true;
	}
	else {
		return false;
	}
}

string Boy::description()const{
	stringstream ret;
	ret << name << "-男-薪资(" << salary << ")-年龄(" << age << ")";
	return ret.str();
}

void Boy::inputBoys(vector &boys) {
	int age;
	string name;
	int salary;
	int n = 1;
	while (1) {
		cout << "请输入第" << n << "位小哥哥的年龄【输入0结束】:";
		cin >> age;
		if (age == 0) {
			break;
		}

		cout << "请输入第" << n << "位小哥哥的姓名:";
		cin >> name;

		cout << "请输入第" << n << "位小哥哥的薪资:";
		cin >> salary;

		n++;
		boys.push_back(Boy(age, name, salary));
	}
}

Main.cpp

#include 
#include 
#include 
#include 
#include   
#include "Boy.h"
#include "Girl.h"
#include 

void autoPair(const vector &boys,const vector &girls) {
	for (int i = 0; i < boys.size(); i++) {
		for (int j = 0; j < girls.size(); j++) {
			if (boys[i].satisfied(girls[j]) &&
				girls[j].satisfied(boys[i])) {
				cout << boys[i].description() << "<==>" <<
					girls[j].description() < boys;
	vector girls;

	Boy::inputBoys(boys);
	Girl::inputGirls(girls);
	
	cout << "\n\n------- 自动匹配 ------\n";
	autoPair(boys, girls);

	system("pause");
	return 0;
}

/*
输入用例:
25 杨过 15000  
28 郭靖 8000
35 段誉 50000
0
18 小龙女 95
25 如花  79
26 秋香  90
26 李莫愁 100
0
*/

第20节 常见错误总结

const的错误用法

Error1-const

#include 
#include 

using namespace std;

class Man{
public:
	Man(){}
	void play() {
		cout << "I am playing ...." << std::endl;
	}
};

int main(void) {
	const Man man;
	man.play();
}

报错: error C2662: “void Man::play(void)”: 不能将“this”指针从“const Man”转换为“Man &”

原因: man是const对象, 但是却调用了非const方法. 类比: 专一男, 不能去夜店玩耍[因为这样很危险, 可能导致专一男变心]

解决方案:

方案1: 把 const Man man; 修改为: Man man;

方案2: 把play方法, 修改为 const方法.

Error2-vector

vector加入的成员是拷贝新成员

Demo

#include 
#include 
#include 
using namespace std;

class Man {
public:
	Man() {}
	void play() {
		count += 10;
		cout << "I am playing ...." << std::endl;
	}
	int getDrinkCount() const {
		return count;
	}
private:
	int count = 0; //一共喝了多少杯酒
};

int main(void) {
	Man zhangFei, guanYu, liuBei;
	vector men;

	// push_back是把参数的值,拷贝给vector
	// men[0]的值和liubBei是相同的,但是,是两个不同的对象
	men.push_back(liuBei);


	men.push_back(guanYu);
	men.push_back(zhangFei);

	men[0].play();
	cout << men[0].getDrinkCount() << endl; //10
	cout << liuBei.getDrinkCount() << endl;  //0

	system("pause");
	return 0;
}

Error2-const

#include 
#include 

using namespace std;

class Man{
public:
	Man(){}
	void play() const {
		cout << "I am playing ...." << std::endl;
	}
};

void play(Man &man) {
	man.play();
}

int main(void) {
	const Man man;
	play(man);
}

原因: 非const引用, 不能对const变量进行引用

注意: const引用, 可以对非const变量进行引用

零基础学习C++系列课程(十一) 持续更新中_第10张图片

解决方案: 修改引用变量, 或者被引用的变量

Error3-static

#include 
#include 

using namespace std;

class Man{
public:
	Man() { count++; }
	void play() const {
		cout << "I am playing ...." << std::endl;
	}

	int getAge() {
		return age;
	}

	static int getCount() {
		getAge();   //error!
		return count;
	}
private:
	static int count;
	int age;
};

int Man::count = 0;

int main(void) {
	Man man1;
	Man man2;
	cout << Man::getCount() << endl;
	
	system("pause");
	return 0;
}

原因: 类的静态方法(static方法) 内, 不能访问实例方法(非static方法)和实例数据成员.

第21节 英语不是障碍:计算机英语加油站

class

private

public

static

const

vector

矢量, 向量

第22节 职场修炼:要不要加入创业团队?

创业机会:程序员在技术沉淀后, 有很多创业机会.

创业方式:

  1. 自己作为核心, 自主创业.

  2. 以技术入股, 和其他伙伴一起创业

  3. 加入创业团队, 获取期权和广阔的发展空间.

创业中的坑:

  1. 判定自己是否合适创业 :创业是个无底洞. 如果只是为了获取自由, 做一个自由程序员, 性价比更高.

  2. 自己不要投入资金

  3. 判断项目是否靠谱

  4. 判断合伙人是否靠谱

第23节 逼格提升:不懂Linux的程序员 不是真正的程序员

  1. 程序员为什么要研究linux?

  2. 需要研究Linux的那些方面?

             2.1)基本命令操作

             2.2)Linux系统编程-服务器开发

     3.应该选择Linux的哪些发行版本?

     4.使用虚拟机方式还是硬盘安装?

第24节 项目练习

项目练习1

创建一个类, 用来表示“玩具”

文具, 有以下数据:

名称,价格,产地。

在使用中,需要获取它的名称, 价格, 产地。

注意:根据自己当前的优惠情况,有一个对外的价格。

零基础学习C++系列课程(十一) 持续更新中_第11张图片

​参考代码:

Toy.h

#pragma once
#include 

using namespace std;

class Toy
{
public:
	Toy();
	Toy(string name, int price, string origin);
	~Toy();

	string getName() const;
	int getPrice() const;
	string getOrigin() const;
	void setDiscount(float discount);
	
private:
	string  name;
	int price;
	string origin; //产地
	float discount = 1.0;  //则扣
};

Toy.cpp

#include "Toy.h"

Toy::Toy()
{
}

Toy::Toy(string name, int price, string origin)
{
	this->name = name;
	this->price = price;
	this->origin = origin;
}

Toy::~Toy()
{
}

string Toy::getName() const
{
	return name;
}

int Toy::getPrice() const
{
	return price * discount;
}

string Toy::getOrigin() const
{
	return origin;
}

void Toy::setDiscount(float discount)
{
	this->discount = discount;
}

Main.cpp

#include 
#include "Toy.h"

int main(void) {
	Toy toy("变形金刚", 5600, "China");
	cout << toy.getName() << ": " << toy.getPrice() 
		   << "[mode in " << toy.getOrigin() << "]"<

项目练习2

定义一个或多个类,来描述以下需求:

定义一个类,来表示某模拟养成游戏中人物:

每个人物, 有昵称,年龄,性别, 配偶, 朋友,

支持的活动有:结婚,离婚, 交友,断交,询问昵称,询问性别,询问年龄, 简介等。

参考代码:

Human.h

#pragma once
#include 
#include 

using namespace std;

typedef enum gender
{
	MAN,        //男
	WOMAN	    //女
}gender_t;

class Human
{
public:
	Human();
	Human(const string &name, gender_t gender, int age);
	~Human();

	string getName() const;
	gender getGender() const;
	int getAge() const;
	Human* getLover() const;
	vector getFriends() const;
	string description() const;
	
	void marry(Human &other);
	void divorce();
	void addFriend(Human &other	);
	void delFriend(Human &other);
private:
	string name;
	gender_t gender; //性别
	int age;
	Human *lover;   //配偶,爱人
	vector friends;
};

Human.cpp

#include "Human.h"
#include 


Human::Human()
{
}

Human::Human(const string & name, gender_t gender, int age)
{
	this->name = name;
	this->gender = gender;
	this->age = age;
}


Human::~Human()
{
}

string Human::getName() const
{
	return name;
}

gender Human::getGender() const
{
	return gender;
}

int Human::getAge() const
{
	return age;
}

Human * Human::getLover() const
{
	return lover;
}

vector Human::getFriends() const
{
	return friends;
}

string Human::description() const
{
	stringstream des;
	des << name << "-age:" << age << "-" << (gender == MAN ? "男" : "女");
	return des.str();
}

void Human::marry(Human &other)
{
	if (gender == other.gender) {
		return;
	}

	this->lover = &other;
	other.lover = this;
}

void Human::divorce()
{
	if (this->lover == NULL) {
		return;
	}

	lover->lover = NULL;
	lover = NULL;
}

void Human::addFriend(Human & other)
{
	friends.push_back(&other);
}

void Human::delFriend(Human & other)
{
	for (auto it = friends.begin(); it != friends.end(); ) {
		if (*it == &other) {
			it = friends.erase(it); //返回下一个成员的"迭代器"
		}
		else {
			it++;
		}
	}
}

Main.cpp

#include 
#include "Human.h"

int main(void) {
	Human lhc("令狐冲", MAN, 25);
	Human ryy("任盈盈", WOMAN, 26);
	Human tbg("田伯光", MAN, 30);
	Human yls("岳灵珊", WOMAN, 20);
	Human cx("冲虚道长", MAN, 55);

	lhc.marry(yls);
	 Human *who = lhc.getLover();
	cout << lhc.getName() << "的配偶是: " << who->description() << endl;
	cout << who->getName() << "的配偶是: " << who->getLover()->description() << endl;

	cout << lhc.getName() << "离婚." << endl;
	lhc.divorce();

	if (lhc.getLover() == NULL) {
		cout << lhc.getName() << "单身" << endl;
	}

	lhc.addFriend(cx);
	lhc.addFriend(tbg);
	vector friends = lhc.getFriends();
	cout << lhc.getName() << "的朋友:" << endl;
	for (int i = 0; i < friends.size(); i++) {
		cout << friends[i]->description() << endl;
	}

	cout << lhc.getName() << "删除好友:" << tbg.getName() << endl;
	lhc.delFriend(tbg);

	friends = lhc.getFriends();
	cout << lhc.getName() << "的朋友:" << endl;
	for (int i = 0; i < friends.size(); i++) {
		cout << friends[i]->description() << endl;
	}

	system("pause");
	return 0;
}

项目练习3

1.定义一个或多个类,来描述以下需求:

汽车,有多个轮胎,一个发动机,品牌,型号, 价格, 行驶里程。

轮胎,有品牌,尺寸,气压。

发动机,有品牌,型号。

参考代码: Tire.h

#pragma once
#include 

using namespace std;

class Tire
{
public:
	Tire(const string &brand="米其林");
	~Tire();
	string descripton() const;
	string getBrand() const;
	float getPressure() const;

private:
	string brand;		//品牌
	float pressure;   //胎压
};

Tire.cpp

#include "Tire.h"
#include 



Tire::Tire(const string &brand)
{
	this->brand = brand;
	this->pressure = 2.5; 
}


Tire::~Tire()
{
}

string Tire::descripton() const
{
	stringstream ret;
	ret << "品牌:" << brand  << "-胎压:" << pressure;
	return ret.str();
}

string Tire::getBrand() const
{
	return brand;
}

float Tire::getPressure() const
{
	return pressure;
}

Engine.h

#pragma once
#include 

using namespace std;

class Engine
{
public:
	Engine();
	Engine(const string &brand,  float version);
	~Engine();

	string description() const;

private:
	string brand;		//品牌
	float version;		//型号, x.x升
};

Engine.cpp

#include 
#include "Engine.h"



Engine::Engine()
{
}

Engine::Engine(const string & brand, float version)
{
	this->brand = brand;
	this->version = version;
}


Engine::~Engine()
{
}

string Engine::description() const
{
	stringstream ret;
	ret << "品牌:" << brand << "-型号:" << version;
	return ret.str();
	return string();
}

Car.h

#pragma once
#include 
#include "Engine.h"
#include "Tire.h"

using namespace std;

class Car
{
public:
	Car();
	Car(const string &carBrand, const string &carVer, int carPrice,
		const string &engineBrand, float engineVer,
		const string &tireBrand = "米其林");
	~Car();

	Engine getEngine();
	Tire* getTire(int i);
	string getBrand();
	string getVersion();
	int getPrice();
	int getMiles();
	string description();

private:
	Engine engine;
	Tire  tires[4];
	string brand;  //品牌
	string version; //型号
	int price;
	int miles;
};

Car.cpp

#include 
#include "Car.h"


Car::Car()
{
}

Car::Car(const string & carBrand, const string & carVer, int carPrice, 
	const string & engineBrand, float engineVer, 
	const string & tireBrand):
	engine(engineBrand, engineVer), tires{ tireBrand, tireBrand, tireBrand, tireBrand }
{
	this->brand = carBrand;
	this->price = carPrice;
	this->version = carVer;
	this->miles = 0;
}


Car::~Car()
{
}

Engine Car::getEngine()
{
	return engine;
}

Tire* Car::getTire(int i)
{
	if (i>=1 && i<=4) {
		return &tires[i];
	}

	return NULL;
}

string Car::getBrand()
{

	return brand;
}

string Car::getVersion()
{
	return version;
}

int Car::getPrice()
{
	return price;
}

int Car::getMiles()
{
	return miles;
}

string Car::description()
{
	stringstream ret;
	ret << "汽车品牌:" << brand << "-" << version << "-$" << price
		<< "\t\t引擎:" << engine.description()
		<< "\t\t轮胎:" << tires[0].descripton();

	return ret.str();
}

测试代码:

#include 
#include 
#include "Car.h"

int main(void) {
	{
		Car car("宝马", "X7", 950000, "宝马", 3.5);
		cout << car.description() << endl;
	}

	system("pause");
	
	return 0;
}

【说明】友元,调整到类的继承之后再讲解

为看书困难的小伙伴推荐视频教程:百度网盘 提取码:r59a

你可能感兴趣的:(C++,c++,学习,开发语言)