鞍山市住房和城乡建设网站,影视网站怎么做内链,嘉兴最大网络平台,华为商城网站建设本专栏记录C学习过程包括C基础以及数据结构和算法#xff0c;其中第一部分计划时间一个月#xff0c;主要跟着黑马视频教程#xff0c;学习路线如下#xff0c;不定时更新#xff0c;欢迎关注。 当前章节处于#xff1a; ---------第1阶段-C基础入门 ---------第2阶段实战… 本专栏记录C学习过程包括C基础以及数据结构和算法其中第一部分计划时间一个月主要跟着黑马视频教程学习路线如下不定时更新欢迎关注。 当前章节处于 ---------第1阶段-C基础入门 ---------第2阶段实战-通讯录管理系统 第3阶段-C核心编程 ---------第4阶段实战-基于多态的企业职工系统 ---------第5阶段-C提高编程 ---------第6阶段实战-基于STL泛化编程的演讲比赛 ---------第7阶段-C实战项目机房预约管理系统 文章目录 一、友元1.1 全局函数做友元1.2 类做友元1.3 全局函数做友元 二、运算符重载2.1 加号运算符重载2.2 左移运算符重载2.3 递增运算符重载2.4 赋值运算符重载2.5 关系运算符重载2.6 函数调用运算符重载 三、继承3.1 继承概述3.2 继承方式3.3 继承中的对象模型3.4 继承构造和析构顺序3.5 继承同名成员处理方式3.6 继承同名静态成员3.7 多继承3.8 菱形继承 四、多态4.1 多态基本概念4.2 纯虚函数和抽象类4.3 虚析构和纯虚析构 一、友元
在程序里有些私有属性也想让类外特殊的有些函数或者类进行访问就需要用到友元的技术目的是让一个函数或者类访问另一个类中私有成员。关键词为friend,友元的是三种实现
全局函数做友元类做友元成员函数做友元
1.1 全局函数做友元
#include iostream
using namespace std;class Person {friend void test(); // 申明友元
public:Person() {name 张三;gender 男;}string name;private:string gender; // 私有属性
};void test() {Person p;cout 姓名 p.name endl;cout 性别 p.gender endl;
}
// 定义友元函数
int main() {test();system(pause);return 0;}姓名张三
性别男
请按任意键继续. . .1.2 类做友元
#include iostream
using namespace std;
class Student {friend class Teacher; // 类做友元
public:Student() {name 张三;score 100;}string name;
private:int score;
};
class Teacher {
public:void test(Student stu) {cout 学生姓名 stu.name endl;cout 学生分数 stu.score endl;}
};int main() {Student stu;Teacher teacher;teacher.test(stu);system(pause);return 0;}学生姓名张三
学生分数100
请按任意键继续. . .1.3 全局函数做友元
#include iostream
using namespace std;
class Student;
class Teacher;
class Teacher {
public:Teacher();
public:void test();void test2();Student* stu;
};class Student {friend void Teacher::test(); // 成员函数做友元
public:Student();
public:string name;
private:int score;
};
Student::Student() {name 张三;score 100;
} // 写在Teacher构造函数之前Teacher::Teacher() {stu new Student;
}
void Teacher::test() {cout 学生姓名 stu-name endl;cout 学生分数 stu-score endl;
}
void Teacher::test2() {cout 学生姓名 stu-name endl;//cout 学生分数 stu-score endl;
}int main() {Teacher teacher;teacher.test();system(pause);return 0;}学生姓名张三
学生分数100
请按任意键继续. . .二、运算符重载
对已有的运算符进行重新定义赋予其另一种功能以适应不同的数据类型。需要重载的运算符为operator
对于内置的数据类型的表达式的运算符是不可能改变的不要滥用运算符重载
2.1 加号运算符重载
#include iostream
using namespace std;
class Person {
public:int m_A 0;int m_B 0;Person() {}Person(int a,int b) {m_A a;m_B b;}// 成员函数加号运算符重载Person operator(const Person p2) { // 用引用节省内存Person temp;temp.m_A this-m_A p2.m_A;temp.m_B this-m_B p2.m_B;return temp;}
};
// 全局函数加号运算符重载
//Person operator(const Person p1,const Person p2) { // 用引用节省内存
// Person temp;
// temp.m_A p1.m_A p2.m_A;
// temp.m_B p1.m_B p2.m_B;
// return temp;
//}int main() {Person p1(1, 2);Person p2(3, 4);Person p3 p1 p2;cout p3.m_A p3.m_A p3.m_B p3.m_B endl;system(pause);return 0;}p3.m_A4 p3.m_B6
请按任意键继续. . .在这里插入代码片2.2 左移运算符重载
#include iostream
using namespace std;
class Person {friend ostream operator(ostream cout,const Person p);
public:Person(int a,int b) {m_A a;m_B b;}
private:int m_A;int m_B;
};// 重载左移运算符
ostream operator(ostream cout,const Person p) {cout p.m_A p.m_A p.m_B p.m_B;return cout;
}
int main() {Person p(10, 20);cout p endl;system(pause);return 0;}p.m_A10 p.m_B20
请按任意键继续. . .2.3 递增运算符重载
#include iostream
using namespace std;class MyInt {friend ostream operator(ostream cout, const MyInt p);
public:MyInt(){}MyInt(int a) {num a;}// 重载前置运算MyInt operator() {num;return *this;}// 重载后置运算MyInt operator(int) { // int 占位符表示后置MyInt temp *this; // 存储当前numnum;return temp; // 返回局部变量只能以值的方式返回}
private:int num;
};
ostream operator(ostream cout, const MyInt p) {cout num p.num;return cout;
}
// 测试前置
void test1() {MyInt a(10);cout a endl;cout a endl;}
// 测试后置
void test2() {MyInt a(10);cout a endl;cout a endl;}
int main() {cout 测试前置: endl;test1();cout 测试后置: endl;test2();system(pause);return 0;}测试前置:
num11
num11
测试后置:
num10
num11
请按任意键继续. . .2.4 赋值运算符重载
#include iostream
using namespace std;
class Person {friend void test();
public:Person(){}Person(int a) {age new int(a); // 在堆区存放a}// 析构函数~Person() {if (age ! NULL) {delete age;age NULL;}}// 重构赋值运算符Person operator(Person p) {age new int(*p.age);return *this;}
private:int *age;
};void test() {Person p1(10);Person p2(20);p1 p2; //不报错深拷贝重新申请一片地址cout p1 *p1.age endl;
}int main() {test();system(pause);return 0;}p120
请按任意键继续. . .2.5 关系运算符重载
重载关系运算符可以让两个自定义类型对象进行对比操作
#include iostream
using namespace std;
class Person {
public:string name;int age;Person(string n,int a) {name n;age a;}bool operator(Person p) {if ((name p.name) (age p.age)) {return true;}else {return false;}}
};void test() {Person p1(A, 12);Person p2(A, 12);if (p1 p2) {cout p1和p2相等 endl;}else {cout p1和p2不相等 endl;}
}int main() {test();system(pause);return 0;}p1和p2相等
请按任意键继续. . .2.6 函数调用运算符重载
函数调用运算符()也可以重载由于重载后使用的方式非常像函数的调用因此称为仿函数仿函数没有固定写法非常灵活
#include iostream
using namespace std;class MyPrint {
public:// 重载函数调用运算符void operator()(string test) {cout test endl;}
};
int main() {MyPrint myprint;myprint(Hello World);system(pause);return 0;}Hello World
请按任意键继续. . .三、继承
3.1 继承概述
继承的好处可以减少重复的代码。 语法class 子类 继承方式 父类 子类也称为派生类父类也称为基类。 子类中的成员包括两大部分一类是从基类继承过来的表现共性一类是自己增加的成员体现个形
#include iostream
using namespace std;
class Animal {
public:void eat() {cout 吃东西 endl;}void play() {cout 出去玩 endl;}
};
class Cat :public Animal { // 继承父类
public:void drink() {cout 小猫喝水 endl;}
};
int main() {Cat cat;cat.eat();cat.play();cat.drink();system(pause);return 0;}吃东西
出去玩
小猫喝水
请按任意键继续. . .3.2 继承方式
继承方式包括三种
公共继承保护继承私有继承
继承关系如下
#include iostream
using namespace std;
// 父类
class Base1 {
public :int a;
protected:int b;
private:int c;
};
// 子类 继承方式为public
class Son1 : public Base1 {
public:void func() {a 100;b 100;//c 100;// 报错父类private不可访问}
};
// 继承方式为protected
class Son2 : protected Base1 {
public:void func() {a 100;b 100;//c 100;// 报错父类private不可访问}
};
// 继承方式为private
class Son3 : private Base1 {
public:void func() {a 100;b 100;//c 100;// 报错父类private不可访问}
};
int main() {Son2 s2;//s2.a 100; // 报错//s2.b 100; // 报错子类继承为protected,类外不可访问Son3 s3;//s3.a 100; // 报错//s3.b 100; // 报错子类继承为private,类外不可访问system(pause);return 0;}3.3 继承中的对象模型
从父类继承过来的成员哪些属于子类对象中
#include iostream
using namespace std;class Base1 {
public:int a;
protected:int b;
private:int c;
};
// 子类 继承方式为public
class Son1 : public Base1 {
public:int s;};
int main() {Son1 s1;cout sizeof s1 sizeof(s1) endl; // 16 继承了父类中的所有非静态成员属性但是private被编译器隐藏无法访问system(pause);return 0;}sizeof s116
请按任意键继续. . .3.4 继承构造和析构顺序
#include iostream
using namespace std;class Base{
public:int a;Base() {cout Base的构造函数 endl;}~Base() {cout Base的析构函数 endl;}
protected:int b;
private:int c;
};
class Son1 : public Base {
public:int s;Son1() {cout Son1的构造函数 endl;}~Son1() {cout Son1的析构函数 endl;}
};
void test() {Son1 s1;
}
int main() {test();system(pause);return 0;}Base的构造函数
Son1的构造函数
Son1的析构函数
Base的析构函数
请按任意键继续. . .现有父类构造再有子类构造然后子类析构最后父类析构
3.5 继承同名成员处理方式
访问子类同名成员直接访问即可访问父类同名成员需要加作用域
#include iostream
using namespace std;class Base {
public:int a;Base() {a 100;}};
class Son1 : public Base {
public:int a;Son1() {a 200;}
};
void test() {Son1 s1;cout 调用Son中的a s1.a endl;cout 调用Base中的a s1.Base::a endl;
}
int main() {test();system(pause);return 0;}调用Son中的a200
调用Base中的a100
请按任意键继续. . .成员函数也是一样当继承了相同名称的同名函数时编译器会将父类的同名函数隐藏想要调用父类的同名函数需要添加作用域。
3.6 继承同名静态成员
#include iostream
using namespace std;class Base {
public:static int a;
};int Base::a 100;
class Son1 : public Base {
public:static int a;
};
int Son1::a 200;void test() {Son1 s1;// 实例化调用cout 调用Son中的a s1.a endl;cout 调用Base中的a s1.Base::a endl;// 类名调用cout 调用Son中的a Son1::a endl;cout 调用Base中的a Son1::Base::a endl;
}
int main() {test();system(pause);return 0;}调用Son中的a200
调用Base中的a100
调用Son中的a200
调用Base中的a100
请按任意键继续. . .静态成员函数也是同理
3.7 多继承
语法 class 子类继承方式 父类1 继承方式 父类2... 多继承可能会引发父类中有同名成员出现需要加作用域区分。 实际开发中不建议使用多继承
#include iostream
using namespace std;class Base1 {
public:Base1() {a 100;}int a;
};
class Base2 {
public:Base2() {a 200;}int a;
};class Son1 : public Base1,public Base2 {
public:int a;Son1() {a 300;}
};int main() {Son1 s1;cout Son1 中的a s1.a endl;cout Base1 中的a s1.Base1::a endl;cout Base2 中的a s1.Base2::a endl;system(pause);return 0;}Son1 中的a300
Base1 中的a100
Base2 中的a200
请按任意键继续. . .3.8 菱形继承
菱形继承概念
两个派生类继承同一个基类又有某个类同时继承这两个派生类
这种继承被称为菱形继承或者钻石继承
#include iostream
using namespace std;
// 基类
class Animal {
public:int age;
};
class Sheep :virtual public Animal { // 虚基类
};
class Tuo :virtual public Animal {
};
class SheepTuo:public Sheep,public Tuo{}; // 菱形继承void test() {SheepTuo t1;t1.Sheep::age 100;t1.Tuo::age 200;cout t1.Sheep::age t1.Sheep::age endl; cout t1.Tuo::age t1.Tuo::age endl;
}
int main() {test();system(pause);return 0;}t1.Sheep::age 200
t1.Tuo::age 200
请按任意键继续. . .四、多态
4.1 多态基本概念
多态是C面向对象三大特性之一一 多态分为两类
静态多态函数重载和运算符重载属于静态多态复用函数名动态多态派生类和虚函数实现运行时多态
静态多态和动态多态区别
静态多态的函数地址早绑定——编译阶段确定函数地址动态多态的函数地址晚绑定——运行阶段确定函数地址
#include iostream
using namespace std;class Animal {
public:// 实现晚绑定virtual void speak() {cout 动物在说话 endl;}
};class Dog :public Animal {
public:void speak() {cout 小狗在说话 endl;}
};class Cat :public Animal {
public:void speak() {cout 小猫在说话 endl;}
};
// 必须是引用
void doSpeak(Animal animal) {animal.speak();
}
int main() {Cat cat;doSpeak(cat);Dog dog;doSpeak(dog);system(pause);return 0;}小猫在说话
小狗在说话
请按任意键继续. . .多态需要满足条件
有继承关系子类重写父类中的虚函数
多态的使用条件 父类指针或应用指向子类对象 实战案例
#include iostream
using namespace std;
class Caulater {
public:int num1;int num2;virtual int getresult() {// 空实现return 0;}
};// 加法
class CaulaterAdd:public Caulater {
public:int getresult() {return num1 num2;}
};// 减法
class CaulaterJian :public Caulater {
public:int getresult() {return num1 - num2;}
};// 乘法
class CaulaterChen :public Caulater {
public:int getresult() {return num1 * num2;}
};void test(Caulater c) {CaulaterAdd ad;ad.num1 10;ad.num2 10;cout ad.getresult() endl;}
int main() {Caulater c;test(c);system(pause);return 0;}20
请按任意键继续. . .4.2 纯虚函数和抽象类
在多态中通常父类中虚函数的实现是毫无意义的主要都是调用子类重写的内容因此可以将虚函数改为纯虚函数。当类中有纯虚函数这个类也称为抽象类 抽象类特点
无法实例化对象子类必须重写抽象类中的纯虚函数否则也属于抽象类
#include iostream
using namespace std;
class Base {
public:// 纯虚函数该类叫抽象类virtual void func() 0;
};class Son:public Base {
public:void func() {cout 调用func函数 endl;}
};int main() {//Base b;// 抽象类无法实例化对象Base * base new Son;Son s; // 重写纯虚函数后可以实例化对象否则子类也是抽象类不能实例化对象base-func();system(pause);return 0;}调用func函数
请按任意键继续. . .实战案例 要求利用多态技术实现本案例提供抽象制作饮品基类提供子类制作咖啡和茶叶。
#include iostream
using namespace std;// 饮品抽象类
class Drink {
public:virtual void func() 0;
};
// 咖啡子类
class Coffee :public Drink {
public:void func() {cout 制作咖啡 endl;}
};
// 茶叶子类
class Tea :public Drink {
public:void func() {cout 制作茶叶 endl;}
};int main() {Drink* c new Coffee;c-func();Drink* t new Tea;t-func();system(pause);return 0;}制作咖啡
制作茶叶
请按任意键继续. . .4.3 虚析构和纯虚析构
多态中如果子类中有属性开辟到堆区那么父类指针在释放时无法调用到子类的析构代码需要将父类中的析构函数改为虚析构或者纯虚析构 虚析构和纯虚析构共性
可以解决父类指针释放子类对象都需要有具体的函数实现
虚析构和纯虚析构的区别 如果是纯虚析构该类属于抽象类无法实例化对象
#include iostream
using namespace std;
class Base {
public:Base() {cout Base的构造函数 endl;}// 虚析构函数//virtual ~Base() {// cout Base的析构函数 endl;// if (name ! NULL) {// delete name;// name NULL;// }//}// 纯虚析构函数virtual ~Base() 0;string* name;
};
Base::~Base(){cout Base的纯虚析构函数 endl;if (name ! NULL) {delete name;name NULL;}
}
class Son :public Base {
public:Son(){cout Son的构造函数 endl;}~Son() {cout Son的析构函数 endl;}};
void test() {Base* b new Son;delete b;
}int main() {test();system(pause);return 0;}Base的构造函数
Son的构造函数
Son的析构函数
Base的纯虚析构函数
请按任意键继续. . .实战案例 电脑主要组成部件为CPU(用于计算)显卡(用于显示)内存条(用于存储) 将每个零件封装出抽象基类并且提供不同的厂商生产不同的零件例救Intel厂商和Lenovo厂商创建电脑类提供让电脑工作的函敌并且调用每个零件工作的接口 测试时组装三台不同的电脑进行工作
#include iostream
using namespace std;
// CPU抽象类
class CPU {
public:// 纯虚函数virtual void caculate() 0;
};
// 显卡抽象类
class VideoCard {
public:// 纯虚函数virtual void display() 0;
};
// 内存条抽象类
class Memory {
public:// 纯虚函数virtual void storage() 0;
};
// Inter的零件
class InterCPU :public CPU {
public:void caculate() {cout Inter的CPU开始计算! endl;}
};
class InterVideoCard :public VideoCard {
public:void display() {cout Inter的显卡开始显示! endl;}
};
class InterMemory :public Memory {
public:void storage() {cout Inter的存储条开始存储 endl;}
};
// Lenovo的零件
class LenovoCPU :public CPU {
public:void caculate() {cout Lenovo的CPU开始计算 endl;}
};
class LenovoVideoCard :public VideoCard {
public:void display() {cout Lenovo的显卡开始显示 endl;}
};
class LenovoMemory :public Memory {
public:void storage() {cout Lenovo的存储条开始存储 endl;}
};
// 电脑类
class Computer {
public:Computer(CPU* c, VideoCard* v, Memory* m) {mc c;mv v;mm m;}void dowork() {mc-caculate();mv-display();mm-storage();}virtual ~Computer() {//cout 电脑的析构函数 endl;if (mc ! NULL) {delete mc;mc NULL;}if (mv ! NULL) {delete mv;mv NULL;}if (mm ! NULL) {delete mm;mm NULL;}}
private:CPU * mc;VideoCard * mv;Memory* mm;
};void start() {// 创建三台电脑cout 第一台电脑 endl;Computer c1(new InterCPU, new InterVideoCard, new InterMemory);c1.dowork();cout 第二台电脑 endl;Computer c2(new LenovoCPU, new LenovoVideoCard, new InterMemory);c2.dowork();cout 第三台电脑 endl;Computer c3(new InterCPU, new InterVideoCard, new LenovoMemory);c3.dowork();
}
int main() {start();system(pause);return 0;}第一台电脑
Inter的CPU开始计算!
Inter的显卡开始显示!
Inter的存储条开始存储
第二台电脑
Lenovo的CPU开始计算
Lenovo的显卡开始显示
Inter的存储条开始存储
第三台电脑
Inter的CPU开始计算!
Inter的显卡开始显示!
Lenovo的存储条开始存储
请按任意键继续. . .