C++——继承、派生、多态

#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;
}

 

 

 

 

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值