C++/CLI——3继承与值类型、操作符重载与异常

2024-01-04 15:20

本文主要是介绍C++/CLI——3继承与值类型、操作符重载与异常,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

C++/CLI——3继承与值类型、操作符重载与异常

继承

C++/cli中的继承用法基本和C#中的用法相同,只不过要注意以下几点:

  1. 标准的C++在继承符号:之后,基类名称之前添加关键字public/protected/private,但是C++/CLI只支持public,所以可写可不写
  2. 标准C++声明抽象基类的方式是在内部至少将一个虚函数=0,设置为纯虚函数,而C++/CLI中则是在类声明后面加上abstract关键字
  3. 抽象函数在C++中叫做纯虚函数,也就是在虚函数后面=0,C++/CLI也支持这样做,另外第二种方式是可以在虚函数后面加上abstract关键字来表示为抽象函数
  4. C++/Cli支持密封类,也就是不能被继承,用sealed关键字ref class Myclass sealed
  5. C++/cli中抽象类和密封类可同时声明,sealed和abstact顺序任意
  6. C++/CLI不支持多继承,只能多继承接口,接口使用interface来声明interface clas IXmlWriter,且接口成员都是公共的和抽象的

案例演示:

interface class ICanShout //定义接口
{void Shout();
};ref class Animal abstract:ICanShout //定义抽象类
{
public:Animal(String^ n,int l);virtual void Eat() abstract;//抽象方法virtual void Shout() =0;//抽象方法String^ name;int legs;
};ref class Dog:Animal
{
public:Dog(String^ n,int l);void Eat() override;virtual void Shout() override;
};ref class Cat :Animal
{
public:Cat(String^ n, int l);void Eat() override;//写不写virtual都可以被重写了,因为基类定义了virtualvirtual void Shout() override;
};Animal::Animal(String^ n, int l)
{this->name = n;this->legs = l;
}Dog::Dog(String^ n, int l):Animal(n,l)
{
}void Dog::Eat()
{Console::WriteLine("我的名字是{0},我吃骨头", name);
}void Dog::Shout()
{Console::WriteLine("我会汪汪叫");
}Cat::Cat(String^ n, int l):Animal(n,l)
{}void Cat::Eat()
{Console::WriteLine("我的名字是{0},我吃鱼", name);
}void Cat::Shout()
{Console::WriteLine("我会喵喵叫");
}
//调用
int main(array<System::String^>^ args)
{Dog^ d = gcnew Dog("tom", 4);d->Eat();d->Shout();Cat^ c = gcnew Cat("jerry", 4);c->Eat();c->Shout();Animal^ a = d;a->Shout();Console::WriteLine("程序结束");
}

值类型

值类型的特点:

  1. 存在栈上
  2. 不进行垃圾回收
  3. 总是直接访问,不使用gcnew
  4. 拷贝类类型是直接拷贝
  5. 不能继承

结构

//使用value关键字
value struct  Point
{//默认publicint x, y;//构造函数不支持默认值
};

结构和类的基本区别:

  • 不能在结构定义时初始化成员,必须在构造器中初始化
  • 不能重写结构默认构造器,因为默认构造器要将所有成员设为默认值
  • 不能有析构和终结器
  • 不支持继承
  • 可实现接口

案例

value struct Line
{String^ name;Point p;
};//使用初始化器,初始化器只能是默认构造函数
Line l = { "线1",{3,4} };
Console::WriteLine(l.name);

枚举

//一定要用public 或者private来限定
//必须这样使用enum  class
public enum  class WeekDay
{Mondy,Tuesday
};
//必须使用类型名称限定
Console::WriteLine(WeekDay::Mondy);

枚举虽然是整数值,但是不能隐式转换,必须这样int day = static_cast<int>(WeekDay::Tuesday);

enum默认是int大小是32位,但是一般1个字节就可以容纳所有的值,为了节省内存,可以增加限定public enum class WeekDay:char

操作符重载

重载操作符的方法和规范基本和C++重载操作符一致,请看下面案例

value struct  IntVal
{
private:int value;
public:IntVal(int v) :value(v) {};int GetValue() { return value; }IntVal operator+(IntVal other){IntVal result(value + other.GetValue());return result;}IntVal operator+(int other){IntVal result(value + other);return result;}static IntVal operator+(int lhs, IntVal rhs){IntVal result(lhs + rhs.GetValue());return result;}
};int main(array<System::String^>^ args)
{IntVal one(1);IntVal two(2);IntVal three = one + two; //IntVal operator+(IntVal other)IntVal t = one + 2; //IntVal operator+(int other)IntVal t = 2 + one ; //static IntVal operator+(int lhs, IntVal rhs)Console::WriteLine(t.GetValue());//输出3Console::WriteLine("程序结束");
}

转换器

上面案例中仅仅实现了static IntVal operator+(int lhs, IntVal rhs),其实还需要实现(IntVal IntVal)\(IntVal,int)其实还有个更简单的办法,也就是重载转换操作符(),将int转换为IntVal。与标准C++不同,在C++中如果定义了int构造器,编译器就允许将int隐式转为IntVal,但是在C++/CLI中必须重载转换操作符

value struct  IntVal
{
private:int value;
public:IntVal(int v) :value(v) {};int GetValue() { return value; }static operator IntVal(int v) //重载转换操作符{return IntVal(v);}static IntVal operator+(IntVal lhs, IntVal rhs)//使用这一个配合重载操作符就可以替代三种签名函数{IntVal result(lhs.value + rhs.value);return result;}
};

另外,与C++不同的是,C++中+并不能自动得到+=,但是在C++/CLI中,重载+会自动得到+=,上面的重载函数完成后,可以实现

IntVal one(1);
one += 2;

递增和递减

标准C++要分别为前++和后++提供两个操作符重载,但是在C++/cli中只需要一个静态重载就可以,需注意要配合重载转换操作符

value struct  IntVal
{
private:int value;
public:IntVal(int v) :value(v) {};int GetValue() { return value; }static operator IntVal(int v) //重载转换操作符{return IntVal(v);}static IntVal operator++(IntVal i)//配合重载转换操作符{i.value++;return i;}
};int main(array<System::String^>^ args)
{IntVal one1(1);IntVal one2(1);Console::WriteLine((one1++).GetValue());Console::WriteLine(one1.GetValue());Console::WriteLine((++one2).GetValue());Console::WriteLine(one2.GetValue());Console::WriteLine("程序结束");
}

image-20240104103844420

引用类型重载操作符

为引用类型重载操作符和为值类型类似,就是要关注对象句柄

ref struct  IntVal
{
private:int value;
public:IntVal(int v) :value(v) {};int GetValue() { return value; }static operator IntVal^(int v) //重载转换操作符{return gcnew IntVal(v);}static IntVal^ operator+(IntVal^ lhs,IntVal^ rhs)//配合重载转换操作符{IntVal^ result = gcnew IntVal(lhs->value + rhs->value);return result;}
};int main(array<System::String^>^ args)
{IntVal^ one = gcnew IntVal(1);IntVal^ two = gcnew IntVal(2);IntVal^ three = one + two;IntVal^ four = two + 2;Console::WriteLine(three->GetValue());Console::WriteLine(four->GetValue());Console::WriteLine("程序结束");
}

image-20240104104435021

异常

C++/CLI中使用异常基本与C#中的使用方法相同。在动态类型转换上,safe_cast转型失败会抛出InvalidCastException,而dynamic_cast则会返回空指针。

这篇关于C++/CLI——3继承与值类型、操作符重载与异常的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/569753

相关文章

从入门到精通C++11 <chrono> 库特性

《从入门到精通C++11<chrono>库特性》chrono库是C++11中一个非常强大和实用的库,它为时间处理提供了丰富的功能和类型安全的接口,通过本文的介绍,我们了解了chrono库的基本概念... 目录一、引言1.1 为什么需要<chrono>库1.2<chrono>库的基本概念二、时间段(Durat

C++20管道运算符的实现示例

《C++20管道运算符的实现示例》本文简要介绍C++20管道运算符的使用与实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录标准库的管道运算符使用自己实现类似的管道运算符我们不打算介绍太多,因为它实际属于c++20最为重要的

Visual Studio 2022 编译C++20代码的图文步骤

《VisualStudio2022编译C++20代码的图文步骤》在VisualStudio中启用C++20import功能,需设置语言标准为ISOC++20,开启扫描源查找模块依赖及实验性标... 默认创建Visual Studio桌面控制台项目代码包含C++20的import方法。右键项目的属性:

c++中的set容器介绍及操作大全

《c++中的set容器介绍及操作大全》:本文主要介绍c++中的set容器介绍及操作大全,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录​​一、核心特性​​️ ​​二、基本操作​​​​1. 初始化与赋值​​​​2. 增删查操作​​​​3. 遍历方

解析C++11 static_assert及与Boost库的关联从入门到精通

《解析C++11static_assert及与Boost库的关联从入门到精通》static_assert是C++中强大的编译时验证工具,它能够在编译阶段拦截不符合预期的类型或值,增强代码的健壮性,通... 目录一、背景知识:传统断言方法的局限性1.1 assert宏1.2 #error指令1.3 第三方解决

C++11委托构造函数和继承构造函数的实现

《C++11委托构造函数和继承构造函数的实现》C++引入了委托构造函数和继承构造函数这两个重要的特性,本文主要介绍了C++11委托构造函数和继承构造函数的实现,具有一定的参考价值,感兴趣的可以了解一下... 目录引言一、委托构造函数1.1 委托构造函数的定义与作用1.2 委托构造函数的语法1.3 委托构造函

C++11作用域枚举(Scoped Enums)的实现示例

《C++11作用域枚举(ScopedEnums)的实现示例》枚举类型是一种非常实用的工具,C++11标准引入了作用域枚举,也称为强类型枚举,本文主要介绍了C++11作用域枚举(ScopedEnums... 目录一、引言二、传统枚举类型的局限性2.1 命名空间污染2.2 整型提升问题2.3 类型转换问题三、C

C++链表的虚拟头节点实现细节及注意事项

《C++链表的虚拟头节点实现细节及注意事项》虚拟头节点是链表操作中极为实用的设计技巧,它通过在链表真实头部前添加一个特殊节点,有效简化边界条件处理,:本文主要介绍C++链表的虚拟头节点实现细节及注... 目录C++链表虚拟头节点(Dummy Head)一、虚拟头节点的本质与核心作用1. 定义2. 核心价值二

Java 继承和多态的作用及好处

《Java继承和多态的作用及好处》文章讲解Java继承与多态的概念、语法及应用,继承通过extends复用父类成员,减少冗余;多态实现方法重写与向上转型,提升灵活性与代码复用性,动态绑定降低圈复杂度... 目录1. 继承1.1 什么是继承1.2 继承的作用和好处1.3 继承的语法1.4 子类访问父类里面的成

C++ 检测文件大小和文件传输的方法示例详解

《C++检测文件大小和文件传输的方法示例详解》文章介绍了在C/C++中获取文件大小的三种方法,推荐使用stat()函数,并详细说明了如何设计一次性发送压缩包的结构体及传输流程,包含CRC校验和自动解... 目录检测文件的大小✅ 方法一:使用 stat() 函数(推荐)✅ 用法示例:✅ 方法二:使用 fsee