首页 > 编程语言 >面向对象(C++)

面向对象(C++)

时间:2023-10-28 15:12:31浏览次数:30  
标签:函数 int 基类 C++ 面向对象 签名 派生类 构造函数

-1 待填坑:运算符重载,模板和泛型编程。文件输入输出

跨文件使用全局变量应该先用extern声明
如果在全局变量和全局函数前面加上static关键字,就无法在其他文件中使用这些变量和函数了。

0、动态内存分配

分配内存:

int* p = new int(4);//注意是一个变量初值为4
int* list = new int[size];//size可以是变量

函数中的局部变量在“栈空间”,但是new出来的是在“堆空间”,是永久的
new 返回的是指针!!!!!!
他们只要不被释放就一直存在,可以在函数中new把这个地址返回出去,会一直存在。
但是如果不返回每一次都new一个p那就会又开一个新的数组。
*的优先级比“.”低,需要加括号,所以有了->,会更快一点。

释放内存

delete p;
delete [] list;//这样才对

1、class

类,构造函数(注意是public)

注意!

如果没有构造函数会缺省无参数构造函数;
如果有其他构造函数,就不会存在无参构造函数了,这可能会导致继承的时候出错(继承的构造函数缺省执行基类无参构造函数)!

and 析构函数

  • 注意创建对象的方式:
Circle a;//如果无参,不能加括号()
Circle a(5);
a = Circle();
a = Circle(5);
  • 避免多次包含:
#ifndef C_H
#define C_H
class Circle
{
public:
...
};

#endif
  • 通常.h中只定义不实现,.cpp中进行实现
  • 实现的时候注意使用
//注意声明可以不写变量名的,就算写了,实现的时候变量名也可以不同的
Circle::getit(int x,int y)
{

}
  • 内联函数 就是inline,编译器会直接把整个复制到调用处,于是小函数会更快因为不需要压入栈调用了

只读成员函数

int getit()const;
表明不会改变class中的数据

静态变量

类中静态变量无需创建对象即可访问
Circle::static_var=1;

拷贝构造函数

看做一种特殊的构造函数,有缺省值,但是是浅拷贝,指针之类的直接赋值过去公用同一个空间。
注意格式:

Course(const Course& course)
{

}

2、继承和多态

继承:

class Circle: public GeometricObject
{

};

访问控制和继承

派生类可以访问基类中所有的非私有成员。因此基类成员如果不想被派生类的成员函数访问,则应在基类中声明为 private。

我们可以根据访问权限总结出不同的访问类型,如下所示:

访问 public protected private
同一个类 yes yes yes
派生类 yes yes no
外部的类 yes no no

一个派生类继承了所有的基类方法,但下列情况除外:

基类的构造函数、析构函数和拷贝构造函数。
基类的重载运算符。
基类的友元函数。

继承类型

当一个类派生自基类,该基类可以被继承为 public、protected 或 private 几种类型。继承类型是通过上面讲解的访问修饰符 access-specifier 来指定的。

我们几乎不使用 protected 或 private 继承,通常使用 public 继承。当使用不同类型的继承时,遵循以下几个规则:

公有继承(public):当一个类派生自公有基类时,基类的公有成员也是派生类的公有成员,基类的保护成员也是派生类的保护成员,基类的私有成员不能直接被派生类访问,但是可以通过调用基类的公有和保护成员来访问。
保护继承(protected): 当一个类派生自保护基类时,基类的公有和保护成员将成为派生类的保护成员。
私有继承(private):当一个类派生自私有基类时,基类的公有和保护成员将成为派生类的私有成员。

泛型程序设计:当程序需要基类对象的时候,可以提供派生类对象

构造函数和析构函数:

调用基类构造函数:

Circle(int sb) : BaseClass(sb)//后面可以用前面传入的参数
{

}

即使没有写后面那个,缺省调用无参构造函数
构造函数链:从基类开始执行
析构函数链:从派生类开始执行
P496:拷贝构造函数的继承

函数重定义

定义一个和基类函数签名相同且返回值相同的函数就可以覆盖基类的。
如果还是想要调用基类的函数,应该使用:
Circle.Fatherclss::toString();

函数重载

签名不同名字相同

签名是什么鬼

在C++中,"签名"指的是函数或方法的唯一标识符,它由函数的名称、参数类型和参数顺序组成。函数签名用于区分不同的函数重载,即在同一作用域内有多个函数具有相同名称但不同参数列表的情况。

函数签名的组成部分包括:

函数名称:这是函数的标识符,用于唯一标识函数的名称。

参数类型:这是函数参数的类型列表,包括参数的数据类型和顺序。参数类型的不同组合会导致不同的函数签名。

参数顺序:参数的顺序也是函数签名的一部分。如果两个函数有相同的参数类型,但参数顺序不同,它们仍然被视为不同的函数。

下面是一个简单的示例来说明函数签名的概念:


// 函数签名示例
int add(int x, int y); // 函数签名为 "add(int, int)"
float add(float x, float y); // 函数签名为 "add(float, float)"
int subtract(int x, int y); // 函数签名为 "subtract(int, int)"

// 重载函数
int calculate(int x, int y); // 函数签名为 "calculate(int, int)"
int calculate(int x, int y, int z); // 函数签名为 "calculate(int, int, int)"

在上面的示例中,有多个函数重载,它们具有不同的函数签名,因为它们的参数类型和/或参数数量不同。函数签名的不同之处在于函数的名称、参数类型和参数顺序,这使得编译器能够区分这些不同的函数,并正确地调用相应的函数。

签名相同,返回值只有一种,不然肯定不能区分了。

函数签名的理解对于函数重载、模板编程和函数指针等C++编程的概念非常重要。


多态

可以用基类指针或引用来引用派生类对象,和泛型编程其实差不多。
形参可以是基类的,但是可以传入派生类的实参。

虚函数和动态绑定

虚函数:在运行时根据目前对象的实际类型选择调用哪一个函数。
在基类中设置为virtual即可,继承的不需要声明为virtual因为默认均为virtual了
例如形参为基类传入派生类的时候,没有virtual调用函数时调用基类的,用了virtual的函数就会调用派生类的。
这个功能叫做(动态绑定)

需要注意:
1、传入的时候必须使用引用或者指针,否则无法动态绑定
2、会重定义的函数应该声明为虚函数,否则调用可能达不到想要的效果。但是如果不需要重定义,那就不要声明为虚函数,因为动态绑定消耗更多时间和系统资源
3、静态绑定:例如有不同的签名的函数的匹配。这是由于函数的性质决定的,但是动态绑定是由于对象的性质决定选择哪一个函数、
4、含有虚函数的类称为多态类型
5、虚函数可以要求派生类必须实现这些函数(其实c++并不能)

抽象类和纯虚函数

  • 抽象类不能创建对象,其中只有抽象函数,他们在具体的派生类中实现。
  • 抽象函数:不能在基类中实现的函数(如GET_TYPE)
  • C++中,抽象函数称为纯虚函数
  • 包含纯虚函数的类就称为抽象类

定义纯虚函数:(真tm抽象)

virtual double getarea() = 0;
virtual double readonly()const = 0;

类型转换: static_cast 和 dynamic_cast

引入:如果形参是基类,在这个函数中我们无法调用子类的函数和其他成员,不好操作

办法1:static_cast<Circle*>(p)->getRadius()//<>内部是转换成的类型,p必须是指针
注意到,这里是强制转换,有可能本来就不是圆的(如矩形)也可以强制转换成圆并造成错误

办法2:dynamic_cast<Circle*>(p)->getRadius()//<>内部是转换成的类型,p必须是指针
如果强制转换错误新指针将会变成NULL,NULL在一些标准库如iostream和cstddef中都有定义


向上转型:派生类->基类 可以直接隐式转换(直接赋值之类都可以)

向下转型:基类->派生类 :利用cast,必须显式转换

标签:函数,int,基类,C++,面向对象,签名,派生类,构造函数
From: https://www.cnblogs.com/lytql/p/17793982.html

相关文章

  • C++指针
    C++指针学习C++指针既简单又有意思。通过指针可以简化一些C++编程任务的执行,还有一些任务,例如动态内存分配,没有指针是无法执行的。因此学习指针是很有必要的。每一个变量都有一个内存位置,每一个内存位置都定义了可使用连字号(&)运算符访问的地址,它表示了在内存中的一个地址。实例......
  • C++ 语法结构--堆
    1.堆介绍「堆heap」是一种满足特定条件的完全二叉树,主要可分为图8-1所示的两种类型。「大顶堆maxheap」:任意节点的值其子节点的值。「小顶堆minheap」:任意节点的值其子节点的值。堆作为完全二叉树的一个特例,具有以下特性。最底层节点靠左填充,其他层的节点都被填......
  • C++字符串
    C++字符串C++提供了两种类型的字符串表示形式:C风格字符串C++引入的string类类型C风格字符串C风格的字符串源于C语言,并在C++中继续得到支持。字符串实际上是使用Null字符终止的一堆字符数组。因此一个以NULL结尾的字符串,包含了组成字符串的字符。下面的声明和初始化创建了......
  • 【C++】继承 ⑪ ( 多继承 | 多继承语法 | 多继承案例 )
    文章目录一、多继承1、多继承基本语法2、多继承子类构造初始化3、多继承中访问父类成员二、多继承案例1、代码示例-简单多继承案例2、代码示例-多继承构造函数案例一、多继承1、多继承基本语法多继承概念:一个子类(派生类)可以继承多个父类(派生类);一个类......
  • C++数组
    C++数组声明数组在C++中要声明一个数组,需要指定元素的类型和元素的数量,如下所示:typearrayName[arraySize];这叫做一维数组。arraySize必须是一个大于零的整数常量,type可以为任意有效的C++数据类型。例如:doublevalance[10];初始化数组doublebalance[5]={1000.0,2.0,......
  • C++常量
    C++常量一、整数常量整数常量可以是十进制,八进制或十六进制的常量。前缀指定基数:0x或0X表示十六进制,0表示八进制,不带前缀则表示十进制。整数常量也可以带一个后缀,后缀是U和L的组合,U表示无符号整数(unsigned),L表示长整数(long),后缀可以是大写,也可以是小写,U和L的顺序任意。85......
  • C++数字及计算
    C++数字及计算C++定义数字#include<iostream>usingnamespacestd;intmain(){ //数字定义 shorts; inti; longl; floatf; doubled; //数字赋值 s=10; i=1000; l=1000000; f=230.45; d=30949.374; cout<<"shorts:"<<s<<en......
  • C++函数定义、声明及调用
    C++函数定义、声明及调用以计算两个数最大值为例,说明C++函数定义、声明及调用#include<iostream>usingnamespacestd;intmax(intnum1,intnum2);//函数声明intmain(){ inta=100;//局部变量声明 intb=200;//局部变量声明 intret; ret=max(a,b);//函数调......
  • c++恶心的char和string
    统计数字出现次数。Char的长度Strlen(char) string的长度.size()函数与.length()Char和string都可以==比较。注意stringa=”1adbcde”,而a[0]是char类型需要转换。 #include<bits/stdc++.h>#include<string>usingnamespacestd;intmain(){intn;charx;cin>>......
  • c++函数指针
    一、函数指针基础知识二、深入探讨函数指针三、auto四、使用typedef进行简化五、指针和const介绍安装使用参考介绍这是一个介绍。安装这是安装说明。使用这是使用说明。参考1.尽可能使用const一、函数指针基础知识完成函数指针需要的工作:获取函数的地址。声......