(继承)virtual与访问控制

之前只注意过访问控制与继承的关系,这边不多说,今天看到代码看到virtual放在private里,并且还有派生类没有override public里的virtual,此时调用时啥情况了,这边有点晕,看下面代码

首先最基本的多态代码

#include <iostream>
#include <string>

using namespace std;

class animal
{
public:
	//animal();
	//~animal();
	virtual void speakout()
	{
		cout << "animal voice voice voice" << endl;
	}
};
class cat :public animal
{
public:
	//cat();
	//~cat();
	virtual void speakout()
	{
		cout << "cat miao miao miao" << endl;
	}
};

int main()
{
	cat ocat;
	animal *panimal = &ocat;
	panimal->speakout();
	getchar();

}

运行结果没有任何问题,结果如下:

如果virtual是私有的,代码如下:

#include <iostream>
#include <string>

using namespace std;

class animal
{
private:
	//animal();
	//~animal();
	virtual void speakout()
	{
		cout << "animal voice voice voice" << endl;
	}
};
class cat :public animal
{
private:
	//cat();
	//~cat();
	virtual void speakout()
	{
		cout << "cat miao miao miao" << endl;
	}
};

int main()
{
	cat ocat;
	animal *panimal = &ocat;
	panimal->speakout();
	getchar();

}

编译就会报错,报错如下,实际上此时放在private里的时候,virtual有和没有一样,都是类的私有成员,只有类内部成员以及友元能够访问

主要是考虑下面一种特殊情况,基类里有virtual A(),派生类继承的时候没有override A(),切A()会调用私有的private virtual,代码如下:

#include <iostream>
#include <string>

using namespace std;

class animal
{
public:
	virtual void speak()
	{
		speakout();
	}
private:
	//animal();
	//~animal();
	virtual void speakout()
	{
		cout << "animal voice voice voice" << endl;
	}
};
class cat :public animal
{
private:
	//cat();
	//~cat();
	virtual void speakout()
	{
		cout << "cat miao miao miao" << endl;
	}
};

int main()
{
	cat ocat;
	animal *panimal = &ocat;
	panimal->speak();
	getchar();

}

其运行结果如下:

再对比如下代码:

#include <iostream>
#include <string>

using namespace std;

class animal
{
public:
	virtual void speak()
	{
		speakout();
	}
private:
	//animal();
	//~animal();
	void speakout()
	{
		cout << "animal voice voice voice" << endl;
	}
};
class cat :public animal
{
private:
	//cat();
	//~cat();
	void speakout()
	{
		cout << "cat miao miao miao" << endl;
	}
};

int main()
{
	cat ocat;
	animal *panimal = &ocat;
	panimal->speak();
	getchar();

}

其运行结果如下:

说明此时的private里的virtual是不能去掉的,如果去掉的话,speak()调用的是类本身的私有函数speakout(),否则调用的是派生类cat里的speakout()函数

当派生类继承了基类里的public speak(),哪怕没做任何修改,去掉private里的virtual,结果调用也是派生类里的speakout(),代码如下:

#include <iostream>
#include <string>

using namespace std;

class animal
{
public:
	virtual void speak()
	{
		speakout();
	}
private:
	//animal();
	//~animal();
	void speakout()
	{
		cout << "animal voice voice voice" << endl;
	}
};
class cat :public animal
{
public:
	virtual void speak()
	{
		speakout();
	}
private:
	//cat();
	//~cat();
	void speakout()
	{
		cout << "cat miao miao miao" << endl;
	}
};

int main()
{
	cat ocat;
	animal *panimal = &ocat;
	panimal->speak();
	getchar();

}

  

运行结果如下:

只能猜测派生类没有继承基类里的public speak(),panimal->speak()调用的是基类里的speak()函数,这时候间接调用的speakout()如果是虚函数则调用派生类的(哪怕是private),否则调用基类的

当继承了基类里的public speak(),panimal->speak()直接就调用了派生类里的speakout(),这时候speakout()是不是虚函数已没有关系

这边的原理我也没搞懂,只知道现在用起来是这样,如果哪位大神知道原理的能和我讲下,不甚感激!!!!!!!!!!!

  

时间: 2024-10-10 13:28:08

(继承)virtual与访问控制的相关文章

C++对象内存分布(3) - 菱形继承(virtual)

1.前言 本篇文章的所有代码例子,如果是windows上编译运行,则使用的是visual studio 2013.如果是RHEL6.5平台(linux kernal: 2.6.32-431.el6.i686)上编译运行,则其gcc版本为4.4.7,如下所示: [[email protected] ~]# gcc --version gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-4) 2.菱形继承类的内存分布 本篇文章主要讨论的是虚继承(virtual)下的内存分

C++ 类的继承一(访问控制)

//类的继承 #include<iostream> using namespace std; /* 面向对象中的继承类之间的父子关系 1.子类拥有父类所有的成员属性和成员函数(包括私有成员变量) 2.子类就是一种特殊的父类 3.子类对象可以当作父类对象使用 4.子类可以拥有父类没有的方法和属性 c++中的类成员访问级别(public,protected,private) 类成员访问级别设置原则 1.需要被外界访问的成员直接设置为public 2.只能在当前类中访问的成员设置为private 3

三种继承方式和访问控制方式对子类成员的影响

定义一个基类BaseClass,从它派生出类DerivedClass,BaseClass有成员函数fn1().fn2(),DerivedClass也有成员函数fn1()和fn2(),在主函数中声明一个DerivedClass对象,分别用DerivedClass的对象以及BaseClass和DerivedClass的指针来调用fn1().fn2(),观察运行结果. 1 #include <iostream.h>  2 class BaseClass {  3 public: void fn1()

c++访问控制与继承

最近,决定认真开始记录自己的学习之路. c++类的访问控制有public.private和protected. 首先要分简单的基类和派生类情况,不是很容易混淆与多级继承时的访问控制.自己原先搞得不清楚,也正是因为没有分开二种情况对待. 在简单的基类和派生类情况中,其访问控制,可以简单总结: public:  1.成员函数   2.类对象   3.友元 4.子类成员函数 private: 1.成员函数  2.友元 protected:  1.成员函数  2.友元  3.子类成员函数 这些基本都清楚

C++ 继承与接口 知识点 小结(一)

[摘要] 要求理解覆盖.重载.隐藏的概念与相互之间的区别:熟记类继承中对象.函数的访问控制:掌握虚函数.虚函数表.虚函数指针的联系:理解区分虚函数和虚继承在虚方法.虚指针在空间分配上的重点与难点:熟练使用多重继承,要求能区分基类的同名函数和基类的空间布局. [正文] 类继承中的覆盖 #include<iostream> using namespace std; class A { protected: int m_data; public: A(int data = 0) { m_data =

C++面向对象编程之继承

一. 封装和继承 1.1 封装的概念 封装:通过访问控制属性对类类型中的属性和行为进行打包和限制. 1.2 继承:通过一种机制表达出类型之间的共性和特性的方式. 继承基本语法: class 子类名 : 继承方式1 父类1,继承方式2 父类2... { 类的定义 }; 继承方式: public  公有方式 private 私有方式 protected 保护方式 1.3 继承的特性 (1) 一个子类类型的对象在任何时候都可以看作基类类型的对象(心里始终要记着). (2) 一个父类类型的对象作为子类对

06_继承与派生

一:继承的概念 面向对象程序设计有 4 个主要特点:抽象.封装.继承和多态性.我们已经讲解了类和对象,了解了面向对象程序设计的两个重要特征一数据抽象与封装,已经能够设计出基于对象的程序,这是面向对象程序设计的基础. 要较好地进行面向对象程序设计,还必须了解面向对象程序设计另外两个重要特征——继承性和多态性.继承性是面向对象程序设计最重要的特征,可以说,如果没有掌握继承性,就等于没有掌握类和对象的精华,就是没有掌握面向对象程序设计的真谛. (1)类之间的关系 has-A, uses-A 和 is-

C++对象模型——&quot;无继承&quot;情况下的对象构造(第五章)

5.2 继承体系下的对象构造 当定义一个object如下: T object; 时,实际上会发生什么事情呢?如果T有一个constructor(不论是由user提供或是由编译器合成),它会被调用.这很明显,比较不明显的是,constructor的调用真正伴随了什么? constructor可能内带大量的隐藏码,因为编译器会扩充每一个constructor,扩充程度视 class T的继承体系而定.一般而言,编译器所做的扩充操作大约如下: 1.记录在member initialization li

虚继承有什么作用

虚继承    在标准I/O库中的类都继承了一个共同的抽象基类ios,那个抽象基类管理流的条件状态并保存流所读写的缓冲区.istream和ostream类直接继承这个公共基类,库定义了另一个名为isotream的类,它同时继承istream和ostream,iostream类既可以对流进行读又可以对流进行写.如果I/O类型使用常规继承,则每个iostream对象可能包含两个ios子对象:一个包含在它的istream子对象中,另一个包含在它的 ostream子对象中.从设计角度讲,这个实现是错误的: