C++ 学习(2)--- virtual

  1. 虚函数

通过基类的指针调用该成员函数时,将根据指针指向的对象类型确定调用的函数,而非指针的类型

是C++ 多态的一种体现,属于 函数的重写, 而非 重载。 要求函数的名称,参数完全一致。

class Animal
{
	public:
		void eat() {
			std::cout << "I'm eating animal food."
		}
};

class Dog : public Animal
{
	public:
		void eat() {
			std::cout << "I'm eating a bone."
		}
};

Animal *animal = new Animal;
Dog *dog = new Dog;

Animal *animal2 = new Dog;

animal ->eat();

cat ->eat();

animal2 ->eat();


输出:
I’m eating animal food.
I’m eating a bone.
I’m eating animal food.

但是,如果把基类中函数设置成 virtual 虚函数,则结果就不同:

class Animal
{
	public:
		virtual void eat() {
			std::cout << "I'm eating animal food."
		}
};

class Dog : public Animal
{
	public:
		void eat() {
			std::cout << "I'm eating a bone."
		}
};

Animal *animal = new Animal;
Dog *dog = new Dog;

Animal *animal2 = new Dog;

animal ->eat();

cat ->eat();

animal2 ->eat();


输出:
I’m eating animal food.
I’m eating a bone.
I’m eating animal bone.

  1. 虚继承

class Biology
{
	public:
		Biology() {
			std::cout << "Biology Constructor."
		}

		~Biology() {
			std::cout << "Biology Destructor."
		}
};

class Animal: public Biology
{
	public:
		Animal() {
			std::cout << "Animal Constructor."
		}

		~Animal() {
			std::cout << "Animal Destructor."
		}
};

class Plant: public Biology
{
	public:
		Plant() {
			std::cout << "Plant Constructor."
		}

		~Plant() {
			std::cout << "Plant Destructor."
		}
};

class SeaAnemone: public Animal, public Plant
{
	public:
		SeaAnemone() {
			std::cout << "SeaAnemone Constructor."
		}

		~SeaAnemone() {
			std::cout << "SeaAnemone Destructor."
		}
};

int main(int argc,char* argv[])
{
	SeaAnemone *SeaAnemone;
	return 0;
}


输出的结果为:
Biology Constructor.
Animal Constructor.
Biology Constructor.
Plant Constructor.
SeaAnemone Constructor.
SeaAnemone Destructor.
Plant Destructor.
Biology Destructor.
Animal Destructor.
Biology Constructor.

这样是有问题的, 基类的构造和析构都被调用了两次。

如果改成虚继承,则不会出现该问题:


class Biology
{
	public:
		Biology() {
			std::cout << "Biology Constructor." << endl;
		}

		~Biology() {
			std::cout << "Biology Destructor." << endl;
		}
};

class Animal: virtual public Biology
{
	public:
		Animal() {
			std::cout << "Animal Constructor." << endl;
		}

		~Animal() {
			std::cout << "Animal Destructor." << endl;
		}
};

class Plant: virtual public Biology
{
	public:
		Plant() {
			std::cout << "Plant Constructor." << endl;
		}

		~Plant() {
			std::cout << "Plant Destructor." << endl;
		}
};

class SeaAnemone: public Animal, public Plant
{
	public:
		SeaAnemone() {
			std::cout << "SeaAnemone Constructor." << endl;
		}

		~SeaAnemone() {
			std::cout << "SeaAnemone Destructor." << endl;
		}
};


输出的结果为:
Biology Constructor.
Animal Constructor.
Plant Constructor.
SeaAnemone Constructor.
SeaAnemone Destructor.
Plant Destructor.
Animal Destructor.
Biology Constructor.

虚基类可以使得从多个类(它们继承自一个类)中派生出的对象只继承一个对象.

而且当 析构函数被调用多次时, 程序会报错的。

  1. 虚析构

#include<iostream>

using namespace std;


class Biology
{
	public:
		Biology() {
			name = new char[16];
			
			std::cout << "Biology Constructor." << endl;
		}

		virtual ~Biology() {
			delete []name;
			std::cout << "Biology Destructor." << endl;
		}
	private:
		char *name;
};

class Animal: virtual public Biology
{
	public:
		Animal() {
			std::cout << "Animal Constructor." << endl;
		}

		~Animal() {
			std::cout << "Animal Destructor." << endl;
		}
};

class Plant: virtual public Biology
{
	public:
		Plant() {
			std::cout << "Plant Constructor." << endl;
		}

		~Plant() {
			std::cout << "Plant Destructor." << endl;
		}
};

class SeaAnemone: public Animal, public Plant
{
	public:
		SeaAnemone() {
			std::cout << "SeaAnemone Constructor." << endl;
		}

		~SeaAnemone() {
			std::cout << "SeaAnemone Destructor." << endl;
		}
};


int main(int argc,char* argv[])
{

	Biology *seaAnemone = new SeaAnemone();

	delete seaAnemone;

	return 0;
}



如果公共基类Biology的析构函数,不声明为virtual, 则 执行会报错。

声明为virtual 则不会报错了。

所以我们一定要注意在基类的析构函数前面加上virtual,使其变成虚析构在C++程序中使用虚函数,
虚继承和虚析构是很好的习惯 可以避免许多的问题

  1. 纯虚函数

在C++中的一种函数申明被称之为:纯虚函数(pure virtual function).它的申明格式如下:

class CShape
{
public:
    virtual void Show()=0;
};

注意红色部分,在普通的虚函数后面加上"=0"这样就声明了一个pure virtual function.

在什么情况下使用纯虚函数(pure vitrual function)?
1,当想在基类中抽象出一个方法,且该基类只做能被继承,而不能被实例化;
2,这个方法必须在派生类(derived class)中被实现;

  1. 虚构造函数

构造函数不能是虚的

  1. Private 虚函数
class A
{
public:
    void foo() { bar();}
private:
    virtual void bar() { ...}
};

class B: public A
{
private:
    virtual void bar() { ...}
};

在这个例子中,虽然bar()在A类中是private的,但是仍然可以出现在派生类中,
并仍然可以与public或者protected的虚函数一样产生多态的效果。
并不会因为它是private的,就发生A::foo()不能访问B::bar()的情况,
也不会发生B::bar()对A::bar()的override不起作用的情况。

这种写法的语意是:A告诉B,你最好override我的bar()函数,但是你不要管它如何使用,也不要自己调用这个函数。

  1. 构造函数和析构函数中的虚函数调用

一个类的虚函数在它自己的构造函数和析构函数中被调用的时候,它们就变成普通函数了,不“虚”了。也就是说不能在构造函数和析构函数中让自己“多态”。

class A
{
public:
    A() { foo();}        // 在这里,无论如何都是A::foo()被调用!
    ~A() { foo();}       // 同上
    virtual void foo();
};

class B: public A
{
public:
    virtual void foo();
};

void bar()
{
    A * a = new B;
    delete a;
}

如果你希望delete a的时候,会导致B::foo()被调用,那么你就错了。
同样,在new B的时候,A的构造函数被调用,但是在A的构造函数中,被调用的是A::foo()而不是B::foo()。

https://www.jianshu.com/p/b470594c81ec

https://www.cnblogs.com/hairuijy/p/10483010.html

https://blog.csdn.net/ithomer/article/details/6031329

https://baijiahao.baidu.com/s?id=1653132502323288772&wfr=spider&for=pc

https://blog.csdn.net/jirryzhang/article/details/79392934

https://blog.csdn.net/false_mask/article/details/81662117

猜你喜欢

转载自blog.csdn.net/wwlhz/article/details/107716699
今日推荐