C++ OOP

本文详细介绍了C++的面向对象编程,涵盖类的基本结构、构造函数与析构函数、访问控制、继承、多态以及运算符重载等内容。重点讨论了类成员的声明与引用,包括public、private和protected的访问控制,以及静态数据成员和this指针的作用。此外,还阐述了友元和命名空间的概念,以及如何处理多重继承下的二义性问题。

C++ OOP

C++ 类

类比结构体增加了操作数据的行为,这个行为就是函数;

class的基本结构

class [类名]
{
	public:
		[数据成员]
		[成员函数]
	protected:
		[数据成员]
		[成员函数]
	private:
		[数据成员]
		[成员函数]
};

另一个类的对象可以作为当前类的成员,但是当前类的对象不能作为该类的成员;
定义class和结构体时,大括号后边要有分号;
class的成员函数可以在class体内实现,也可以在class之外,通过域运算符 :: 实现;
类的数据成员需要初始化,成员函数需要实现代码,但是类的数据成员不能在类的声明中初始化;
允许空class存在 class CppClass{};

class对象的声明与引用

声明
[类名] [对象名称]
CppClass obj_;

引用

[对象名称].[成员名称]
[对象名称].[成员名称](参数表)			//函数引用

[对象指针名]->[成员名称]
(*[对象指针名]).[成员名称]
[对象指针名]->[成员名称](参数表)		//对象指针方式

构造函数与析构函数

构造函数

构造函数是可以带参数的;
构造函数是可以重载的;
复制构造函数:构造函数的参数是一个已经初始化的类的类对象;

析构函数

析构函数名标识符是在类名标识符前面加’~'号;
一个类中只能定义一个析构函数;
析构函数不能重载;
析构函数和构造函数都不能使用return返回值,也不需要void关键字;

类成员

public; private; protected
  • public 的成员对外可见,对内也可见;
  • private 的成员对外不可见,对内可见;
  • protected 的成员对外部可见,对内可见,且对派生类是可见的;

在这里插入图片描述

Reference: http://www.runoob.com/cplusplus/cpp-inheritance.html

inline
class example
{
	private:
		int num;
	public:
		inline void pub_num();
}; 
  • 定义在类体中,即使没有使用inline关键字,该成员函数也会被认为是内联成员函数;
static数据成员
class example
{
	public:
		static unsigned int num; 		//定义静态数据成员
		static void print_num()			//定义静态成员函数
		{
			std::cout << num << std::endl;
		}
};
  • 一个类中的静态数据成员,允许使用类名直接访问example::num = 0;
  • 定义静态数据成员时候,通常需要在类外对静态数据成员进行初始化;
  • 在一个类中,静态数据成员是被所有类对象所共享的,无论存在多少个类的对象,类的静态数据成员始终只有一份;
  • 静态数据成员可以是当前类的类型,其他数据成员只能是当前类的指针或者引用类型?;
  • 静态数据成员可以作为成员函数的默认参数,类的普通数据成员不能作为默认参数;
  • 类的静态成员函数只能访问类的静态数据成员,不能访问普通数据成员;
  • 静态成员函数不能定义为const成员函数,意味着静态成员函数末尾不能使用const关键字;
  • 静态成员函数定义的时候,如果函数的实现代码位于类体之外,则在函数的实现部分不能标识static关键字;
this
  • 为什么需要this指针: 对于类的非静态成员,每一个对象都有自己的一份拷贝,即每个对象都有自己的数据成员,不过成员函数是对象共享的,所以在调用成员函数的时候,需要this指针来区分自己的数据成员,在每个类的成员函数(不包括静态成员函数)中都隐含一个this指针;
  • 待补充
嵌套类

在C++中,允许在一个类中定义另一个类,这叫做嵌套类;

  • 虽然嵌套类是在外部类内部定义的,但是外部类不能访问嵌套类的私有成员;
  • 仅外部类可以使用嵌套类,嵌套类在其他类域或作用域中不可见;
  • 虽然在外部函数中,嵌套类不可见,但是可以通过外部类的类域作为限定符来定义嵌套类out_class::in_class obj_name;
局部类

类的定义不仅可以放在头文件中,也可以放在源文件中,同时也可以放在函数中,这样在函数中定义的类被称为局部类;

  • 在函数之外不可以访问局部类;

friend 友元

使用friend关键字可以定义友元,让特定的函数后者别的类的所有成员函数对本类的私有数据成员进行读写;

namespace

在定义命名空间的时候,通常在头文件中生命命名空间中的函数,在源文件中定义命名空间中的函数;如此使用中,在源文件定义函数时,要使用命名空间名作为前缀;

  • 命名空间可以嵌套;
  • 可以定义未命名的命名空间,未命名的命名空间被设置为全局命名空间;
namespace的定义
namespace [名称]
{
	[常量,变量,函数的定义]
}
namespace的使用
[命名空间名称]::[成员];

也可以使用using namespace语句;

using namespace std;

继承

继承:使得一个类可以从现有的类中派生,而不必定义一个新的类;

class [派生类名]:[继承方式][父类名]		//':'表示子类和父类之间的继承关系;
{
	[访问控制修饰符]:
		[成员声明列表]					//派生类新增的成员;
};
  • 继承方式: public; protected; private;

访问控制

public继承: public -> public; protected -> protected; private -> 不可访问;
protected继承: public -> protected ; protected -> protected; private -> 不可访问;
private继承: public -> private; protected -> private; private -> 不可访问;

构造函数,析构函数

构造函数: 先调用父类的构造函数,然后调用子类的构造函数;
析构函数: 先调用子类的析构函数,然后调用父类的析构函数;

当父类存在带参数的构造函数

默认情况下,子类会调用父类的默认构造函数;
若想使用父类的带参数构造函数,需要显式方式调用父类的构造函数;

覆盖父类的成员函数

如果在子类中定义了一个和父类一样的成员函数,那么一个子类的对象在调用函数的时候,调用的是子类的成员函数;

  • 如果想要访问父类的成员函数,需要显式地使用父类名;

      child_class child_obj;
      child_obj.father_class::father_function();
    
  • 如果子类覆盖了父类的成员函数,则父类中所有的同名成员函数(重载的函数)都会被隐藏;

多重继承

多重继承:子类从多个父类中继承公有和受保护的成员;

class [派生类名] : [继承方式][父类名_1], [继承方式][父类名_2]		//':'表示子类和父类之间的继承关系;子类名之间用','隔开
{
	[访问控制修饰符]:
		[成员声明列表]					//派生类新增的成员;
};
二义性

二义性: 子类在调用成员函数的时候,会先在自身域内寻找,如果找不到,会在基类中寻找,但是当多个父类中有同名成员函数的时候,会不知道调用哪个成员函数,这称为二义性;

  • 可以通过显式的声明来解决

      class child_class : public father_class_1, public father_class_2
      {
      	**** ****
      }
    
      child_class child_obj;
      
      child_obj.father_class_1::father_function();
      child_obj.father_class_2::father_function();
    
构造函数调用顺序

多重继承中构造函数的调用顺序以派生表中的声明顺序为准,调运顺序是按照父类的前后顺序进行的;

  • 派生表是多重继承定义中继承方式后边的内容;

多态

多态: C++中,多态性是指不同功能的函数可以用同一个函数名;

C++有两种联编方式:静态联编,动态联编;根据联编时刻的不同,存在两种不同类型的多态,1: 函数重载; 2: 虚函数;

运算符重载

运算符本质上是一个函数,对运算符的重载也就是对函数的重载;

重载运算符的声明:

operator [类型名]();
  • operator是需要重载的运算符;
  • 运算符重载没有返回值,类型名就代表了返回的类型;
  • 重载运算符不能改变原有运算符的操作数;
  • 重载运算符不能改变原有运算符的优先级;
  • 重载运算符不能改变原有运算符的结合性;
  • 重载运算符不能改变原有运算符的语法结构;

允许重载的运算符

在这里插入图片描述

Reference: http://www.runoob.com/cplusplus/cpp-overloading.html

例子

#include <iostream>
using namespace std;
class example
{
	public:
		example(int num_)
		{
			num = num_;
		}
		example operator+(example b)
		{
			return example(num + b.num);
		}
	private:
		int num;
};

void main()
{
	example e_a(1);
	example e_b(2);
	example output(0);
	output = e_a + e_b;
}

++ and - -

对于++和- -运算符;
如果重载运算符没有参数,则表示是前置运算;
如果重载运算符使用整数作为参数,则表示后置运算;

Reference: 《C++从入门到精通》《C++ Primer Plus》

### C++ 面向对象编程(OOP)相关的面试题 C++ 是一种支持面向对象编程(OOP)的编程语言,其核心特性包括封装、继承和多态。以下是与 C++ 面向对象编程相关的常见面试题及其答案。 #### 1. 什么是面向对象编程(OOP),以及它在 C++ 中是如何实现的? 面向对象编程是一种以对象为中心的编程范式,强调数据的封装和代码的复用性。在 C++ 中,OOP 的主要特性通过类(class)、对象(object)、继承(inheritance)、多态(polymorphism)等机制实现[^1]。 #### 2. 解释 C++ 中的封装。 封装是 OOP 的核心概念之一,它将数据(属性)和操作数据的方法(函数)绑定在一起,并隐藏内部实现细节。在 C++ 中,可以通过使用 `private` 和 `protected` 访问修饰符来实现封装[^1]。 ```cpp class EncapsulationExample { private: int privateData; // 私有成员变量 public: void setPrivateData(int value) { privateData = value; } // 公有成员函数 int getPrivateData() const { return privateData; } }; ``` #### 3. 什么是继承?C++ 中如何实现继承? 继承是 OOP 的一种机制,允许一个类(派生类)从另一个类(基类)中继承属性和方法。C++ 支持单继承和多继承,继承的关键字为 `class Derived : access-specifier Base`,其中 `access-specifier` 可以是 `public`、`protected` 或 `private`[^1]。 ```cpp class Base { protected: int baseValue; public: Base(int val) : baseValue(val) {} }; class Derived : public Base { public: Derived(int val) : Base(val) {} void printBaseValue() { std::cout << baseValue << std::endl; } }; ``` #### 4. 多态的概念是什么?C++ 中如何实现多态? 多态是指同一个接口可以表示不同的类型或动作的能力。C++ 中的多态主要通过虚函数(virtual function)和重载(overloading)实现。虚函数允许派生类重新定义基类中的函数行为[^1]。 ```cpp class Animal { public: virtual void sound() { std::cout << "Animal makes a sound" << std::endl; } }; class Dog : public Animal { public: void sound() override { std::cout << "Dog barks" << std::endl; } }; ``` #### 5. 什么是纯虚函数?C++ 中如何定义纯虚函数? 纯虚函数是一个没有具体实现的虚函数,用于强制派生类必须实现该函数。包含纯虚函数的类被称为抽象类,不能直接实例化。纯虚函数通过 `= 0` 定义[^1]。 ```cpp class AbstractClass { public: virtual void pureVirtualFunction() = 0; // 纯虚函数 }; ``` #### 6. C++ 中的构造函数和析构函数是如何工作的? 构造函数用于初始化对象,而析构函数用于释放对象占用的资源。构造函数可以在定义时自动调用,而析构函数会在对象销毁时自动调用。C++ 还支持拷贝构造函数和移动构造函数。 ```cpp class ConstructorDestructorExample { public: ConstructorDestructorExample() { std::cout << "Constructor called" << std::endl; } ~ConstructorDestructorExample() { std::cout << "Destructor called" << std::endl; } }; ``` #### 7. 什么是静态成员函数和静态成员变量? 静态成员函数和静态成员变量属于类本身,而不是某个具体的对象。它们可以通过类名直接访问,而不必创建类的实例。 ```cpp class StaticExample { public: static int staticVariable; // 静态成员变量 static void staticFunction() { std::cout << "Static function called" << std::endl; } }; int StaticExample::staticVariable = 0; // 初始化静态成员变量 ``` #### 8. C++ 中的友元函数和友元类是什么? 友元函数或友元类可以访问类的私有和受保护成员。它们通过 `friend` 关键字声明,通常用于需要突破封装限制的场景[^1]。 ```cpp class FriendExample { private: int privateData; public: FriendExample(int val) : privateData(val) {} friend void friendFunction(FriendExample& obj); // 声明友元函数 }; void friendFunction(FriendExample& obj) { std::cout << "Private data: " << obj.privateData << std::endl; } ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值