C++中面向对象编程
面向过程即是面向函数的语言,当遇到复杂的问题时,把任务拆分。通过各个函数实现相对简单的功能,最后在主函数中调用。
一切皆对象,凡是证据一定空间的事物都可以称为对象。而面向对象的语言都是把任务当作对象去解决
这个世界是因为对象相互交互而运行的,而要实现一个比较复杂的系统,最好是模拟现实世界的规律即面向对象。
类的封装就是类本身,把属性(变量)和方法(函数)封装到class中;
类的继承 在C++中子类可以继承父类的一些属性和方法,站在巨人的肩膀上,瞬间拥有父类的一些东西;
多态 同一类事物,有相同的操作,但是具体到不同对象,结果不一样.在C++中基类常用虚函数实现共性的部分,在子类中对父类的继承并构造以后,同一个函数到不同对象中可以实现自己的功能。
类的继承
父类--->子类
基类--->派生类
继承,is a 关系 , 子类 is a 父类 , 狸花猫是猫,猫 is a 动物
写代码的时候,要考虑现实情况.
父子对象 成员同名的问题:
class animal() {
public:
string sex;
string kind;
void show() { cout<<"in animal show()"<<endl;}
private:
int age;
};
class cat : public animal{
public:
string kind;
void show() {cout<<"in cat show()"<<endl;}
private:
};
cat xiaohua; 报错吗??? 可行吗?? ----见代码 ----父亲被隐藏
xiaohua.show();
cout<<xiaohua.kind <<endl;
#### public private protected
1.修饰类成员
class cat {
public:
类内类外都可以访问
protected:
限制类外访问,和private区别只在继承方面
private:
限制类外访问
};
2.继承方面
生活中: 1.完全继承 子对象-自己用-给自己孩子-给外人 public : 子对象自己用,类外用,继承给孩子
2.私有继承 自己用,限制继承--给外人非法 private : 子对象自己用
3.保护继承 自己用,可以继承给孩子,给外人非法 protected:
class animal {
public:
string kind;
int weight;
void show(){ cout<<"animal kind="<<kind<<" sex="<<sex<<endl;}
protected:
string sex;
void sleep() {cout<<"animal sleep()"<<endl;}
private:
string nothong;
void ruce() {cout<<"animal ruce"<<endl;}
};
######### public 继承 99% ######
class cat:public animal {
公有继承, 父亲的private部分 不能直接使用
父亲的public protected成员 属性不变, 即父类中public成员在子类中还是public,protected还是不变
效果等同于如下: 增加了父亲的代码
--public:
--string kind;
--int weight;
--void show(){ cout<<"animal kind="<<kind<<" sex="<<sex<<endl;}
--protected:
--string sex;
--void sleep() {cout<<"animal sleep()"<<endl;}
public:
protected:
private:
};
//类外访问
cat xiaohua;
xiaohua.kind = "lihuamao"; 正确,父类public成员,通过public继承,再子类中还是pubic成员
xiaohua.sex=" man" ; 错误,父类的protected,通过public继承,在sub class中,还是保护成员,不允许类外访问
xiaohua.nothong = "xx"; 错误,父亲的私有不允许被子类访问
class lihuamao:public cat {
同理,因为animal的public protected成员,都已经属于cat中的public和protected,继续继承
可以使用 animal的public protectd成员
};
####### 私有继承 ######### 限制类外访问 和继承
class cat: private animal {
父亲的私有部分,cat肯定不能访问
父亲的public protectd成员,都降级为private成员了
效果等同于:
--private:
--string kind;
--int weight;
--void show(){ cout<<"animal kind="<<kind<<" sex="<<sex<<endl;}
--private:
--string sex;
--void sleep() {cout<<"animal sleep()"<<endl;}
};
cat xiaohua;
xiaohua.kind = "bosimao"; 非法,因为private继承,将所有成员降级为private
class lihuamao : public cat{
子类lihuamao中,不能直接访问 animal中的元素,###继承失败....
};
################### 保护继承 ##################
class cat:protectd animal{
父类私有部分,肯定不行.
父类public protectd 成员都降级为 protected成员 :
效果等同于:
--protectd:
--string kind;
--int weight;
--void show(){ cout<<"animal kind="<<kind<<" sex="<<sex<<endl;}
--protectd:
--string sex;
--void sleep() {cout<<"animal sleep()"<<endl;}
};
cat xiaohua.kind = "xxx"; 非法,因为protectd继承,父类所有成员都降级为protected,禁止类外访问
class limaohua: public cat {
孙子lihuamao继承
--protectd:
--string kind;
--int weight;
--void show(){ cout<<"animal kind="<<kind<<" sex="<<sex<<endl;}
--protectd:
--string sex;
--void sleep() {cout<<"animal sleep()"<<endl;}
};
#include<iostream>
using namespace std;
class people{ //父类 描述事物的 普世的 通用的 都有的概念
public:
string kind;
int weight;
people(){ cout<<"in people( )"<<endl; }
people(string kind,int weight,string sex,int age)
{ cout<<"in people( ...)"<<endl;
this->kind=kind; this->weight=weight;this->sex=sex;this->age=age;
}
~people() {cout<<"~people()"<<endl;}
void eat(void){cout<<"people eat()"<<endl;}
void run(void){cout<<"people run()"<<endl; }
void set_sex(string sex) {this->sex=sex;}
string get_sex() {return sex;}
void set_age(int age) {this->age=age;}
int get_age(void){return age;}
private: //限制类外访问,包括限制 子对象的直接访问
string sex;
int age;
void la(void){cout<<"people la()"<<endl;}
};
/*
class 子类:父类 {
父类的东西
子类的新东西
}
*/
class student: public people{
//已经拥有了people的##所有东西##,只是父亲的private部分不可以直接访问
//然后我们只需要添加子类特有的即可
public:
string name;
/*
####构造函数:
子类的构造函数在执行的时候,首先去寻找并执行父类的构造函数 (初始化父亲的那一部分)
之后,再执行子类的部分(初始化子类的部分)
子类构造,如何执行调用父亲的哪一个构造....... 如果不指定,调用父类的默认构造
子类构造(参数1,参数2,参数3....):父亲构造(arg1,arg2,....)
{
只用来初始化子类特有的
}
*/
student() {} //会call father's default structure
student(string name,int age,string sex) : people("student type" ,5,sex,age)
{
cout<<"in student(...)"<<endl;
this->name=name;
}
/*
析构函数: 当子对象被销毁,执行子对象的析构, 在子对象析构执行完毕后,会自动调用父对象的析构
*/
~student()
{
cout<<"~student()"<<endl;
//调用父亲的析构,不需要写,g++自动帮你添加代码
}
void show(){ cout<<"name="<<name<<" sex="<<get_sex()<<" age="<<get_age()<<endl;}
void studentStudy(void){cout<<"student study" <<endl;}
void studentTest(void){cout<<"student test"<<endl;}
private:
void run(void){cout<<"student run"<<endl;}
string color;
};
int main()
{
//student xiaohuangng;
student xiaohuang("huang",3,"woman"); /* 当子类对象产生,立即出发子类构造,
子对象构造函数,首先寻找父类构造函数并执行,之后在执行自己的*/
xiaohuang.show();
cout<<"####### father class private show##########"<<endl;
/* xiaohuang.sex = "man"; 非法的
父类有私有成员, 父类希望这些private都只能在父类中使用.
子类是不能够直接访问的( 子类中有这些东西 ),如果子类想访问,
只能通过父类提供的public 方法
*/
xiaohuang.set_sex("man");
cout<<"xiaohuangng sex="<<xiaohuangng.get_sex()<<endl;
cout<<"########## public member show########"<<endl;
xiaohuang.type= "student type";
xiaohuang.weight=3;
xiaohuang.name="xiaohuang";
xiaohuang.eat();
xiaohuang.studentchMouse();
//main退出之后,进程技术,释放所有空间(包括 xiaohuang, ),执行xiaohuang的析构( ~student() )
}
多态: 是面向对象中一种很重要的特性.
同一类事物,有相同的操作,但是具体到不同对象,结果不一样.
生活中到处都是多态.
父类的run函数要允许子类覆盖它: 即子类也要实现run
如何允许子类覆盖掉该函数呢?
使用virtual修饰函数, 该函数为一个 虚函数,允许子类覆盖.
使用父类指针指向子类对象, 可以屏蔽掉子类的 个性,只关注整体的共性.
纯虚函数:
父类的虚函数,一般在子类中都会重新实现,被覆盖掉. 我们几乎不会使用父亲虚函数
就没有必要实现了, 我们可以直接不写. virtual void run() = 0;
//我们发现父类的虚函数 几乎不会被使用,可以不写,直接给0
//这样的函数,称为 纯虚函数:虚函数没有函数体/实现
//拥有纯虚函数的类,是不完整的( 因为函数没有完成),这种类 称为 虚基类
// person xiaowang; 非法,因为虚基类 不完整,大小都确定的.
// person * p; 合法的. 虚基类可以定义指针,因为 指针大小固定
虚析构:
问题: p是父类指针,虽然指向子类对象,但是只能访问父类的部分,所以这里调用的是父类的析构
子类部分没法释放,怎么办
基类的析构改为 虚函数
这是一个很常用的方法:
如果可以,所有的析构 都要写成虚函数.
#include<iostream>
using namespace std;
class animal{
public:
/*父类的run函数要允许子类覆盖它: 即子类也要实现run
如何允许子类覆盖掉该函数呢?
使用virtual修饰函数, 该函数为一个 虚函数,允许子类覆盖.
*/
virtual void run() {cout<<"animal run"<<endl;}
void bark(){cout<<"animal bark"<<endl;}
private:
string kind;
};
class cat:public animal {
public:
void run() {cout<<"cat run"<<endl;} //会覆盖掉 父类的 虚函数
void catchMouse(){cout<<"cat catchMouse"<<endl;}
private:
string name;
};
class dog:public animal {
public:
void run(){cout<<"dog run"<<endl;}
void watchdog(){ cout<<"watch dog"<<endl;}
private:
void goupao(){ }
};
int main()
{
dog xiaowang;
xiaowang.run(); // dog run
cat xiaohua;
xiaohua.run(); // 打印cat run;
animal *pt = &xiaowang;
pt->run(); //打印结果是 子类的run
/*
原理是:
子类的 run函数覆盖了父类的run(父类的run"消失")了.
*/
}
继承和多态的实例
#include<iostream>
using namespace std;
/*
定义一个人类为 基类, 包含姓名,年龄,性别ID,工作 娱乐方法; 定义子类,
实现律师(增加属性方法) 完成工作 娱乐等方法
码农子类(增加属性方法), 完成工作 娱乐等方法
完成构造和析构,至少三种(父类构造)
*/
class person{
public:
virtual void work() =0;
//我们发现父类的虚函数 几乎不会被使用,可以不写,直接给0
virtual void funy() =0;
//这样的函数,称为 纯虚函数:虚函数没有函数体/实现
//拥有纯虚函数的类,是不完整的( 因为函数没有完成),这种类 称为 虚基类
person() { }
// person xiaowang; 非法,因为虚基类 不完整,大小都确定的.
// person * p; 合法的. 虚基类可以定义指针,因为 指针大小固定
person(string xname,string xsex,intxage):name(xname),age(xage),sex(xsex)
{ }
private:
string name;
int age;
string sex;
};
class lawer:public person {
public:
void work() { cout<<" da guan si "<<endl;}
void funy() { cout<<" bei law book"<<endl;}
lawer(string name,int workid,int age,string sex):person(name,sex,age )
{
this->workid=workid;
}
private:
int workid;
};
class coder :public person {
public:
void work() { cout<<" coding "<<endl;}
void funy() { cout<<" shua github "<<endl;}
private:
string workage;
};
int main()
{
person *p = new lawer("wanglushi",123789,39,"man");
p->work();
p->funy();
delete p;
p = new coder ;
p->work();
p->funy();
delete p;
}