#include <iostream>
#include <string>
#include <stack>
using namespace std;
/*
子类与父类作用域访问权限示例
class Animal //sizeof(Animal) = 12
{
private:
int a;
public:
int b; //会被继承 但无法在子类中被访问
protected:
int a1;
};
class Cat:private Animal //sizeof(Cat) = 20=12+8
{
public:
int c;
void show()
{
//子类无法访问父类的私有成员 如a
//cout<<c<<" "<<a<<" "<<b<<" "<<c<<" "<<d<<endl;
//父类的protected成员可以被子类访问,外界不能访问 如a1
cout<<a1<<" "<<c<<" "<<d<<endl;
}
private:
int a;
int d;
};
class whileCat:public Cat //继承方式默认为public
{
public:
void show()
{
cout<<c<<endl;
//cout<<d<<endl; 子类不能访问父类的私有成员 如变量d a
//cout<<a<<endl;
}
};
int main()
{
//stack<int>c;
//c.empty(); stack库函数的使用
Cat a;
cout<<sizeof(Animal)<<endl;
cout<<sizeof(Cat)<<endl;
return 0;
}
*/
/*
//cat继承animal示例 自己练习的
//运用string类实现
class Animal
{
public:
Animal(string name)
:_name(name) //放在初始化的一定是构造 如果没有构造 表示已经都构造过了
{}
void eat()
{
cout<<_name<<":eat eat..."<<endl;
}
void call()
{
cout<<_name<<"Animal call..."<<endl;
}
protected:
string _name;
};
class Cat:public Animal
{
public:
Cat(string name)
:Animal(name)
{}
void call()
{
cout<<_name<<":miao miao..."<<endl;
}
};
int main()
{
Cat c1("cat");
c1.eat();
c1.call();
}
*/
#if 0
class Animal
{
public:
Animal(char* name)
{
_name = new char[strlen(name)+1];
strcpy_s(_name, strlen(name)+1, name);
}
virtual ~Animal()
{
cout<<"~Animal()"<<endl;
delete []_name;
}
void eat()
{
cout<<_name<<":eat eat eat..."<<endl;
}
virtual void call()
{
cout<<"Animal call call call..."<<endl;
}
protected:
char* _name;
};
class Dog : public Animal
{
public:
Dog(char* name)
:Animal(name)
{
}
~Dog()
{
}
void call()
{
//调用父类的_name
cout<<_name<<":wang wang wang..."<<endl;
}
};
int main()
{
Dog d1("阿黄");
d1.eat();
d1.call();
Dog d2("黑子");
Animal an("动物");
//d2 = an;子类对象不能调用父类的对象
an = d2; //父类可以调用子类的对象
d2.call();
return 0;
}
#endif
/*
class A
{
public:
A(int tmp = 10)
{
a = tmp;
}
int a;
protected:
int b;
private:
int c;
};
class Aa:public A
{
public:
int a;
int a1;
Aa(int tmp1 = 10, int tmp2 = 20)
:A(tmp1) //用初始化列表先构造父类
{
a = tmp1;
a1 = tmp2;
}
void show()
{
cout<<a<<endl;
cout<<a1<<endl;
cout<<A::a<<endl; //访问父类的a要加类名作为定义域
}
protected:
int b1;
private:
int c1;
};
class B
{
public:
void showa()
{
cout<<"B::void showa()"<<endl;
}
void showb()
{
cout<<"B::void showb()"<<endl;
}
void show()
{
cout<<"B::void show()"<<endl;
}
};
class C:public B
{
public:
void showa() //子类中的成员方法会隐藏父类中的成员方法
{
cout<<"C::void showa()"<<endl;
}
void showb(int b)
{
cout<<"C::void showb(int b)"<<endl;
}
int show()
{
cout<<"C::int show()"<<endl;
return 0;
}
};
int main()
{
//父类A与子类Aa函数的访问
Aa a;
a.show(); //调用子类的show函数10 20 10
cout<<a.a<<endl; //子类10
cout<<a.Aa::a<<endl; //父类10
return 0;
C c;
c.showa(); //c::showa
c.showb(10);//c::showb
c.show();//c::show
c.B::showb(); //b::showb子类访问父类show函数的方式
return 0;
}
*/
/*
class Base
{
public:
Base(int a)
:_a(a)
{}
//show函数与~Base函数前根据情况加visual
virtual void show()
{
cout<<"Base::void show()"<<endl;
}
virtual ~Base()
{
cout<<"Base::void show()"<<endl;
}
private:
int _a;
};
class Drive : public Base
{
public:
Drive(int a, int b)
:Base(a),_b(b)
{ }
void show()
{
//Base::~Base();析构和构造其实被子类继承下来了 只是被隐藏了
cout<<"Drive::void show()"<<endl;
}
~Drive()
{
cout<<"Drive::~Drive()"<<endl;
}
private:
int _b;
};
int main()
{
//多态的例子
Base *pb = new Drive(10,20);
pb->show(); //output: Base void show
cout<<typeid(pb).name()<<endl; //class Base*
cout<<typeid(*pb).name()<<endl; //动多态发生的条件:访问类型时产生作用 output:class Base
Base base1(10);
Drive der(10,20);//先构造父类(基类) 再构造子类(派生类)
//Base* pb = &der; 定义指针不会对析构的顺序产生影响
cout<<"------------"<<endl;
Drive *pd = new Drive(10,20);
Base *pb = new Base(10);
//Base*pb0 = pb;
//delete pb0; 只调用父类的析构函数 没有析构子类 内存泄漏 改正:应使子类的析构函数为虚函数
delete pd;
cout<<"----------"<<endl;
delete pb;
//依赖指针手动释放 会产生内存泄漏
return 0;
}
*/
/*类与类之间的关系
*组合:一个类是另一个类的一部分
*代理:一个类的方法是另一个类方法的子集
*继承:一个类是另一个类的一种 代码的复用
*面向对象的特征:抽象 继承 多态 封装
*
*父类 继承方式 子类 外界
*public public public public
protected protected protected
private private
*protected public protected protected
protected protected protected
private private
*private public 不可访问 不可访问
protected protected 不可访问
private 不可访问
*在子类加作用域访问父类的成员
*子类跟父类成员变量的关系:同名父类的成员变量就会被隐藏(与public protected private等作用域无关)
*构造顺序
*先构造成员对象 再构造类对象
*先构造父类 再构造子类
*父类需要提供参数必须先在子类的初始化列表里进行初始化 提供参数 然后子类再进行使用
*析构顺序
*先析构子类 再析构父类
*析构子类的时候会自动析构父类
*成员方法之间的关系
*重载:作用域相同 函数名相同 参数列表不同 子类跟父类的作用域不相同 所以不能重载
*隐藏:子类会隐藏父类中成员方法名相同的成员
*覆盖:只会发生在虚函数表中 如果子类的成员方法跟父类的虚成员方法相同(同返回值 同名 同参数列表)则构成覆盖关系 子类覆盖父类 调用父类的方法
*父类对象不能给子类对象赋值 如dog = animal; //error 可访问但不存在
*子类对象可以给父类对象赋值 如animal = dog; //ok 用子类对象直接构造父类对象
*animal = dog; //先用子类对象构造父类对象 然后给父类对象赋值
*父类指针不能赋值给子类的指针 如:
Dog *pdog = &dog;
Animal *panimal = &animal;
pdog = panimal; //error
panimal = pdog; //ok
*子类指针能赋值给父类的指针
*virtual虚函数 虚表指针存放了一个虚函数表
*父类中的虚函数继承到子类中同样是虚函数 (同返回值 同名 同参数列表)
*多态
*静多态:编译时期的多态 重载(编译期调用) 模板
*动多态:继承中的多态 运行时期的多态 virtual关键字 运行时才知道调用哪个成员方法
*动多态发生的条件:指针的解引用,解引用的一定是虚函数或类型
*思考:
*1.什么时候析构函数必须写虚函数?
答:存在基类指针指向堆上的子类对象的时候
*2.构造函数 inline函数 static函数能否写成虚函数?
答:static:不可以,没有this指针,无法找到对象的地址,就无法找到虚函数表。static函数可以不依赖对象调用
inline:不可以,编译期在调用点展开,relese版本没有地址
构造函数:不可以,构造函数的作用就是构造对象,而对象存在于虚表的前四个字节,自相矛盾(对象没有产生 无法调用)
析构函数:可以
纯虚函数:没有实现的虚函数
拥有纯虚函数的类称为虚基类 虚基类不能实例化对象
MVC用继承多态实现
链表用map()表实现
子类的多态用基类的虚函数实现
*/
//拥有纯虚函数的类称为虚基类 虚基类不允许实例化对象
class Animal
{
public:
Animal(const string& name)
:_name(name)
{}
virtual void call() = 0; //纯虚函数
/*
Animal(char* name) //Animal(const string name)
{
_name = new char[strlen(name)+1];
strcpy_s(_name,strlen(name)+1, name);
}
~Animal()
{
cout<<"~Animal()"<<endl;
delete []_name;
}
virtual void call()
{
cout<<"Animal call call call..."<<endl;
}
*/
protected:
string _name;
};
class Cat:public Animal
{
public:
Cat(const string &name)
:Animal(name)
{ }
void call()
{
cout<<_name<<":miao miao miao..."<<endl;
}
};
class Dog:public Animal
{
public:
Dog(const string &name)
:Animal(name)
{ }
void call()
{
cout<<_name<<":wang wang wang..."<<endl;
}
};
int main()
{
//Animal an("动 物");
//an.call();
Dog dog("阿 黄");
dog.call();
Cat cat("星 星");
cat.call();
Animal *pa = &cat;
pa->call(); //父类call()前加virtual调用子类的call函数
cout<<"-----------"<<endl;
//两个子类的call方法产生互换
int *p1 = (int *)&cat;
int *p2 = (int *)&dog;
int tmp = *p1;
*p1 = *p2;
*p2 = tmp;
Cat *pc = &cat;
Dog *pd = &dog;
pc->call();
pd->call();
return 0;
}