继承(上):【C++进阶学习】第一弹——继承(上)——探索代码复用的乐趣-CSDN博客

前言:

目录

一、隐藏

1.1 隐藏的概念

1.2 隐藏的两种类型

二、派生类的默认成员函数

三、继承与友元

四、继承与静态成员

五、总结


一、隐藏

1.1 隐藏的概念

1.2 隐藏的两种类型

具体来说,有以下两种情况:

成员变量隐藏:
如果子类中出现了和父类同名的成员变量,则子类中的这个成员变量会隐藏父类中的同名成员变量。例如:

class Parent {
public:
    int a;
};

class Child : public Parent {
public:
    int a; // 此处的 a 会隐藏 Parent 中的 a
};

int main() {
    Child c;
    c.a = 10; // 此处修改的是 Child 中的 a,而不是 Parent 中的 a
    return 0;
}

成员函数隐藏:
如果子类中出现了和父类同名的成员函数,则子类中的这个成员函数会隐藏父类中的同名成员函数。例如:

class Parent {
public:
    void func() {
        cout << "Parent::func()" << endl;
    }
};

class Child : public Parent {
public:
    void func() {
        cout << "Child::func()" << endl;
    }
};

int main() {
    Child c;
    c.func(); // 此处调用的是 Child 中的 func(),而不是 Parent 中的 func()
    return 0;
}
class Parent {
public:
    int a;
};

class Child : public Parent {
public:
    int a;
};

int main() {
    Child c;
    c.a = 10; // 此处修改的是 Child 中的 a
    c.Parent::a = 20; // 此处修改的是 Parent 中的 a
    return 0;
}

总之,在 C++ 中的继承中,隐藏是一种特殊的机制,需要注意避免误用。

二、派生类的默认成员函数

class Parent {
public:
    Parent(int a) : m_a(a) {}
    int m_a;
};

class Child : public Parent {
public:
    Child() : Parent(0) {} // 此处的构造函数会自动调用 Parent 的构造函数,并传入 0 作为参数
};

同时,如果我们没有提供任何析构函数,那么 C++ 编译器也会自动为我们提供一个默认的析构函数,其析构函数的函数体为空。例如:

class Parent {
public:
    ~Parent() {}
};

class Child : public Parent {
public:
    ~Child() {} // 此处的析构函数会自动调用 Parent 的析构函数
};

需要注意的是,如果我们提供了任何一个构造函数或析构函数,那么 C++ 编译器就不会再为我们提供默认的构造函数或析构函数了。这时如果我们需要使用默认的构造函数或析构函数,需要我们自己显式地提供。(析构顺序为先派生类再基类)

另外,对于拷贝构造函数和拷贝赋值运算符来说,如果我们没有提供任何拷贝构造函数和拷贝赋值运算符,那么 C++ 编译器会自动为我们提供一个默认的拷贝构造函数和拷贝赋值运算符,其行为是浅拷贝(Shallow Copy),即直接拷贝成员变量的值。例如:

class Parent {
public:
    Parent(int a) : m_a(a) {}
    int m_a;
};

class Child : public Parent {
public:
    Child(int a, int b) : Parent(a), m_b(b) {}
    int m_b;
};

int main() {
    Child c1(1, 2);
    Child c2(c1); // 此处调用的是 Child 的默认拷贝构造函数,直接拷贝 m_a 和 m_b 的值
    return 0;
}
class Parent
{
public:
	Parent(int a)
		:_a(a)
	{}
	int _a;
};
class Child :public Parent
{
public:
	int* _b;

	Child(int a, int b)
		:Parent(a),
		_b(new int(b))         //深度拷贝
	{}
	~Child()
	{
		delete _b;
		_b = nullptr;
	}
	Child(const Child& c)
		:Parent(c)
	{
		_b = new int(*c._b);
	}
	Child& operator=(const Child& c)
	{
		if (this != &c)
		{
			_a = c._a;
			delete _b;
			_b = new int(*(c._b));			
		}
		return *this;
	}
	void Print()
	{
		cout << "_a:" << _a << " " << "_b:" << *_b << endl;
	}
};
int main()
{
	Child c1(1, 2);     
	Child c2(c1);      //此处调用的是c2的深度拷贝
	c2.Print();

	Child c3 = c1;
	c3.Print();
	return 0;
}

运行结果:

【C++进阶学习】第二弹——继承(下)——挖掘继承深处的奥秘-LMLPHP

我们通过两张图来总结一下:

【C++进阶学习】第二弹——继承(下)——挖掘继承深处的奥秘-LMLPHP

【C++进阶学习】第二弹——继承(下)——挖掘继承深处的奥秘-LMLPHP

三、继承与友元

在C++中,友元关系不能被继承,因为友元关系是独立于类定义的,并不是类的成员。因此,如果在父类中声明了一个友元函数或友元类,子类无法继承这种关系。

下面是一些相关知识点:

#include<iostream>
#include<string>
using namespace std;
class Base {
public:	
	friend void friendFunction(Base&);
protected:
	int value;
};

class Derived : public Base {
public:
	// friendFunction 在 Derived 中不是友元函数,需要重新声明
	friend void friendFunction(Derived&);
};

void friendFunction(Base& base) {
	// 可以访问 Base 的私有成员
	base.value = 10;
}

void friendFunction(Derived& derived) {
	// 可以访问 Derived 的私有成员
	derived.value = 20;
}

int main() {
	Derived derived;
	friendFunction(derived);
	return 0;
}

四、继承与静态成员

在 C++ 中,类可以包含静态成员变量和静态成员函数,其中静态成员变量属于类本身,而不是类的某个对象,因此它们可以在不创建类对象的情况下被访问。

下面是一个简单的例子:

#include<iostream>
using namespace std;

class Parent {
public:
	static int a;
};

int Parent::a = 10;      //静态成员的定义只能在类外进行

class Child : public Parent {
public:
	static int a;      //类中只能声明静态成员
};

int Child::a = 20;       //静态成员的定义只能在类外进行

int main() {
	cout << Parent::a << endl;    //输出10
	cout << Child::a << endl;     //输出20
	return 0;
}

运行结果:

【C++进阶学习】第二弹——继承(下)——挖掘继承深处的奥秘-LMLPHP

在上面的例子中,Parent 类和 Child 类都有一个静态成员变量 a,它们各自拥有自己的实现。在 main 函数中,我们可以直接通过类名来访问这些静态成员变量。

总之,在 C++ 中,静态成员在继承中的行为与普通成员有所不同,需要注意其使用方法。

五、总结

感谢各位大佬观看,创作不易,还请各位大佬一键三连!!!

【C++进阶学习】第二弹——继承(下)——挖掘继承深处的奥秘-LMLPHP

06-18 02:23