JAVA 转 C++ 必记 PartA_java转换c++方法-程序员宅基地

技术标签: C++  c++  c++-primer  

JAVA 转 C++ 必记 PartA

判断条件
if(condition)
condition 不一定是要返回true or false 可以判断操作是否成功。
if(cin >> a) a是int类型 然后输入一个字符类型 条件就马上不成立。
当condition 为 0 时条件等于false

变量初始化
int units_sold = 0;
int units_sold = {0}; //不会执行转换
int units_sold{0}; //不会执行转换
int units_sold(0);

定义和声明
extern int i ; 声明
int i = 0; 定义
extern int i = 10; 定义 赋初始值的时候就抵消了 extern 的作用。
引用
int test = 1024; 赋值
int &refTest = test; refTest 引用了test 修改refTest 等于修改了 test
int &refTest ; 错误引用必须初始化。
引用对象初始化一次之后,不能再次引用其他对象。引用对象充当副本的作用。
空指针
int *p = 0;
int *p = nullptr;
int *p = NULL;

错误: int val = 0; int *p = val //不能将val赋值到指针。

void*指针
void* 指针可以指向任意值,但是void* 指针不能访问其指向对象。
用法如下:
int val = 156;
void *vp = &val;
int ip = (int)vp;

指向指针的引用
int val = 10;
int *p = &val;
int *&ref = p; //p指针的引用
cout << *ref << endl; //ref 等于10

const限定符
const int bufSize = 1024; //类似于final
如果想多个文件之间共享bufSize
extern const int bufSize = fcn(); //在file_1.cc 定义并初始化
extern const int bufSize; //在file_1.h 定义 共享const对象必须要使用extern关键字
常量指针与指向常量的常量指针
const int val = 123; //常量
const int *pa = &val; //指向常量的指针,指向可以修改。
const int *const pb = &val; //指向常量的常量指针,则指向无法修改。
指向常量的指针称为 底层const(low-level const) 常量指针称为 顶层const(top-level const)

constexpr
constexpr 常量表达式
const int val = 123 ; 属于constexpr 属于常量表达式
const int limit =val + 123; 属于constexpr ,常量表达式在编译过程之中已经知道结果的,如果在编译过程中无法得知结果的就不属于常量表达式
constexpr int mf = 20 //成立
constexpr int limit = mf +133; //成立
constexpr int sz = size() //如果size函数是属于constexpr 函数就成立 否则 不成立。constexpr 函数在编译之中已经得知结果。
IO库、string、自定义类 这些类型不属于字面值类型 所以不能定义为constexpr
constexpr 的指针只对指针有效 对指向的对象无关。
const int *p = nullptr; //指向一个常量
constexpr int *p = nullptr; //常量指针
constexpr const int *p = &intVal //指向一个常量的常量指针

定义别名
typedef char pstring; //定义指针的别名,如果没有就等于定义char类型的别名
char val = ‘a’;
pstring pst = &val;

C++ 11 规定了新的方法定义别名
using myChar = char;
using myCharp = char *;
myChar c = ‘a’;
myCharp cp = &c;

auto自动识别类型
自动类型识别
int i=0;
auto ci = i; //ci 是 int 类型
auto ip = &i; // ip 是 int 指针类型
const auto a = i; // a 是int常量类型
auto b = a; //顶层的const被忽略 b 是一个int类型 不是const int
auto ia = &a; //ia 是指向常量的int指针类型
auto &q = ci; //q是int的引用类型
auto d = q; // d 是int 类型,因为q作为一个引用类型始终都是作为其指向对象的同义词存在。不过除了以下的decltype有所不同。
decltype 类型指示符
decltype 是通过表达式 获得所属的类型的
const int ci = 133 , &refci = ci;
decltype(ci) a = 0; //a 是int类型
decltype(refci) b = a; //b 是int 引用类型
int i = 342, *ip = &i, &r = i;
decltype(r+0) c; //c 是int类型
decltype(*ip) d = i; //d 是 int 引用类型
decltype(i) e; // e 是int 类型
decltype((i))f = i; //f 是int 引用类型 这里要注意如果外面加了括号就是引用类型
decltype(fun()) g = 323; // fun 函数返回的实际类型,但是不会执行函数体

避免类重复定义使用预处理指令

ifndef LEARNINGCPP_BOOK_H //如果未定义LEARNINGCPP_BOOK_H 则加载以下代码 这有效避免重复定义。简单来说就是如果你包含了两次这个头文件也不存在问题因为他只加载一次。

define LEARNINGCPP_BOOK_H

include

include

include “User.h”

using namespace std;
class Book {

};

endif //LEARNINGCPP_BOOK_H

数组注意
int val[10] ; //int类型数组
int *val[10] ; //int 指针类型 数组
int (*val)[10]; //int 类型数组 指针
int (&val)[10] = test; //int 类型的数组 引用
int *(&val)[10] = test; //int 指针类型的数组 引用
int *(*val)[10]; //int 指针类型的数组 指针
string nums[10] = {“one”,”two”,”three”,”four”,”five”}
string *p2 = nums; //等价于 string *p2 = &nums[0];
auto ia2(nums); //ia2是一个指针 指向数据的第一个元素 等价于 string *ia2 = &nums[0];
decltype(nums) nums2 = {“one”,”two”,”three”,”four”,”five”} // decltype等于是数组类型 要注意 有别于 auto
size_t sz = sizeof(a) / sizeof(*a); //获得数组个数

sizeof表达式
Sales_data data,*p;
auto size = sizeof(Sales_data) //获得类的对象占用空间大小
auto size = sizeof data; //获得类的对象占用空间大小
auto size = sizeof p; //获得指针占用空间大小
auto size = sizeof *p; //获得指针指向的对象占用空间大小
auto size = sizeof data.a; //获得data对象的a 属性占用空间大小
auto size = Sales_data::a; //获得Sales_data类对象的a 属性占用空间大小

类型转换
static_cast<类型>(对象) 可以转行所有非底层const对象
double price_double = 100.563;
void* price_voidP = &price_double;
double p = static_cast

define NDEBUG

include

using namespace std;
int main() {
cout << “application started …” << endl;
int d = 1;
assert(d == 1);
cout << “application go to the second part” << endl;
assert(d == 3);
cout << “application ready success !” << endl;
}
注意:如果不是调试模式需要将#define NDEBUG写在#include 的上面。

还有其他调试时候可能使用到的预处理变量
int main() {

ifdef NDEBUG

cout << "function name : " << __func__ << endl;
cout << " file name : " << __FILE__ << endl;
cout << " TIME : " << __TIME__ << endl;
cout << " DATE : " << __DATE__ << endl;
cout << " LINE : " << __LINE__ << endl;

endif

}
函数指针
int sum(int a, int b);
int main() {
int (*p)(int, int) = sum; //定义函数指针必须和函数签名一致。
cout << p(10, 10) << endl;
}
int sum(int a, int b) {
return a + b;
}
当然函数指针也可以支持重载如果函数指针的类型定义的函数签名与其中目标其中一个重载函数一致,则使用相应的函数进行赋值。
int sum(int a, int b);
int sum(double a,double);
int main() {
int (*p)(int, int) = sum; //使用int 类型参数的函数。
cout << p(10, 10) << endl;
}
我们也可以使用auto 或者 decltype 进行定义函数指针签名
int sum(int a, int b);
int main() {
auto p = sum; //注意如果函数重载了就不能够使用此方法。
cout << p(10, 10) << endl;
}

int sum(int a, int b);
int main() {
decltype(sum) p = sum; //注意decltype返回的是函数类型,所以需要加号说明定义的是指针类型,而且和上面的auto一样,只能够对没有重载的方法有效。
cout << p(10, 10) << endl;
}
我们还可以利用using 或者 typedef 进行定义别名
using fun_a = int(*)(int,int);
typedef int(*fun_b)(int,int);
int sum(int a, int b);
int main() {
fun_a pa = sum;
fun_b pb = sum;
cout << pa(10, 10) << endl;
cout << pb(10, 10) << endl;
}
而且我们可以利用函数指针作为参数,以及返回值,但是返回值经过测试后发现,直接写函数的签名定义返回值会发生编译错误,所以返回值我们需要定义别名。但是在C++11的宝典上是可以这样做的,不过我暂时未发现这种语法导致编译错误的原因。
using fun_a = int(*)(int,int);
int sum(int a, int b);
auto testFunc(int a,string(*cb)(bool)) -> fun_a;
string callback(bool status);
int main() {
cout << “execute testFunc and execute method by return : \n ” << testFunc(10,callback)(3,3) << endl;
}
auto testFunc(int a,string(*cb)(bool)) -> fun_a{
cout << a << endl;
cb(true);
return sum;
}
int sum(int a, int b) {
return a + b;
}
string callback(bool status){
cout << “callback executed , result : ” << status << endl;
}

类的基本介绍
C++类一般在创建过程当中就分开两个文件,一个头文件,和类定义文件。
就由定义类型的基本数据成员开始介绍,定义类中的函数以及类中的数据成员都有访问作用域,也跟java一样,有private 和 public。private 只有在本类和相应的对象中访问,同时在C++当中拥有一种名叫友元的概念去解决类似于protected修饰符的场景。
首先以下是定义类的成员数据的基本范例:
class Product {
public:
Product(string product_name, double product_price) :
productName(product_name), price(product_price) {}; //类的构造函数【后面详解】
private: //所有访问修饰符都是从定义开始一下的元素都是采用这种访问修饰,直到第二个修饰符为结束,如果没有下个修饰符就直到类定义作用域结束为止。
double price; //定义了商品类的价格,访问修饰符为private。
string productName;
string productDesc;
};

细谈对象函数中的this指针
class Product {
public:
Product &setPrice(double product_price); //返回对象自身的引用
double getPrice() const; //重点在const身上,const是代表this指针是指向常量对象的指针,也就是说this在这个函数的是不可更改this中的任何数据的,这个有别于java中的final变量中的对象,因为final变量中对象是可以改变对象中的属性的(如果属性不是定义了final的话)
….Product类后面省略

现在来看看定义:
Product& Product::setPrice(double product_price) { //由于我们是在头文件以外的地方定义函数的,所以需要在函数名前面添加作用域运算符 :: 作用域添加类的名字。
this->price = product_price; //这里没有定义为const的this指针所以可以修改对象中的元素
return this; //这里返回要带 因为返回类型是要返回引用。
}
double Product::getPrice() const {
return this->price; //这里定义了const this所以不能够修改对象中的元素,否则就会编译错误。
}
当然上面都使用了this显性调用对象的东西,但是也可以像JAVA一样忽略this,这个看心情。

struct 和 class的区别
其实两个的区别不想java,他们的定义也非常简单,struct默认的访问修饰是public,class的默认访问修饰是private,如果自定义了访问修饰就根本上是一个屌样了。

默认构造函数
和JAVA一样都会有个默认的构造函数,如果定义了其他构造函数,默认的构造函数就会失效,所以如果你需要自定义之后保留构造函数就必须像JAVA一样显性定义。
class Product {
public:
Product() = default;
Product(string product_name, double product_price) : productName(product_name), price(product_price) {};

Product() = default; ——— 使用C++ 显性定义默认的构造函数。

构造函数初始化参数,的方法也非常特别:
Product(string product_name, double product_price) : productName(product_name), price(product_price) {};
在 “:” 号 后面跟的是需要初始化的数据成员名称,然后()跟的是形参名称,多个数据成员用,号隔开,然后{}中的是初始化之后,需要执行的代码,所以不同于JAVA{}中执行的不是初始化了已经是属于赋值了。所以初始化不要在函数体进行,因为如果有引用的话就会报错,因为引用是无法赋值的,而且必须要有一个初始值。

初始化顺序问题
注意:由于种种问题再初始化类的成员的时候,最好按照声明成员数据的顺序来进行初始化,例如以下例子就会出现问题:
class Product{
public:
Product() = default;
Product(string product_name) :
productName(product_name) , productDesc(productName) {};
private:
string productDesc;
string productName;
double price;
}; 由于productDesc比之前先定义,所以初始化的时候先初始化productDesc 而且productName是一个未初始化的值,所以就会有无法预计的错误。而且在某些情况,初始化的顺序和定义的顺序不一致也会获得警告。

在C++11中有一种叫做委托构造函数
就是说一个构造函数将构造的任务委托给其他构造函数来处理,这种称为委托构造函数。
范例如下:
class Product {
public:
Product(string product_name = “”) : Product(product_name,product_name,0) {};
Product(string product_name, string product_desc, double product_price) :
productName(product_name), productDesc(product_desc), price(product_price) {};
};

有一个构造函数有全部参数的初始化,然后第一个只有一个参数的构造函数并将初始化的工作委托给第二个构造函数。注意:我们在第一个构造函数当中添加了一个默认值,所以这个函数也等同于默认构造函数,因为他可以无参。

友元以及类接口
友元是为特定的函数或者类提供访问相应类中私有成员的方法。使用方法非常简单,就是在类的定义当中,写上friend开头 然后写上函数声明即可,如果是类的方法可以直接写类的作用域,或者直接写整一个类。
class Product {
friend void printProduct(Product &data);
public:
….中间省略一万字
};
void printProduct(Product &data); //同一份头文件,但是不在类定义的作用域当中的函数。这个称谓类的接口,提供类的其他功能供调用。所以这个函数没有调用类中私用数据以及方法的权限,定义友元声明后,该函数就可以方法product类的所有私有成员。
下面是定义整一个类的友元:
class Product {
friend class 类名;
friend 类名::函数名(参数…);

mutable 成员数据,可以在const this 指针的成员中进行数据更改:
class Product {
public:
…… 中间省略一万字
double getPrice() const;
private:
…… 中间省略一万字
mutable int visit_count = 0;
};

类的定义
double Product::getPrice() const {
this->visit_count += 1; //由于
return this->price;
}

关于类成员函数的const this指针重载。
class Product {
public:
const Product &showProduct() const; //const this 指针的重载。
Product &showProduct();
……
private:
……
};
使用场景在于,链式编程。如果返回的是一个常量的对象,则再调用有修改业务的成员函数就会错误。这样的重载主要看的是调用的对象是不是const 如果是const则调用const的成员函数 如果不是就调用非const的成员函数。现在看看定义
const Product &Product::showProduct() const {
cout << “Product name : ” << productName << “\nprice : ” << price << endl;
return *this;
}

Product& Product::showProduct() {
cout << “Product name : ” << productName << “\nprice : ” << price << endl;
return *this;
}
Product product(“TEST”,100.55);
const Product second_product(“TESTconst”,123);
product.showProduct();
second_product.showProduct(); 调用const版本的成员函数

关于类中的成员数据是类本身,需要注意!!!因为在定义类的过程之中,类是没有完全定义的,所以如果将类本身作为类的成员数据来说,这样编译器不知道分配多少内存,所以只能定义指针或者引用。
class Product {
public:
private:
Product sub_product; //不能这样搞啊!!!
};
所以要改成:
class Product {
public:
private:
Product *sub_product; //product对象的指针
};

类的作用域深度理解
由于我们经常将类的成员定义写在类的定义之外,所以我们需要在成员函数中写上类名::这样的类作用域符,但是需要注意的一点就是从::之后就已经进入了类的作用域了。
class Product {
typedef int Index;
….. }; 我在类中写了一个别名,这个别名在类的作用域中是生效的所以根据上述所说的以下的函数定义就成立了:
void Product::showIndex(Index val) {}
由于从::开始之后就属于类的作用域范围所以这里也可以使用Index这个别名。(红色部分就是类的作用域范围)

关于类的隐性转换问题:
void printProduct(Product data); //这个方法可以存入一个字符串参数
因为我们定义了一个构造函数有一个字符串参数就可以生成一个Product对象
Product(string product_name = “”) : Product(product_name,product_name,0) {};

调用方法如下:
string productName = “iphone7”;
printProduct(productName);
其实对于这样的调用似乎非常容易混淆,所以最好不要使用。而且这里只有一级转换所以我们不能printProduct(“iphone7”)这样去写,因为这样就等价于需要从C的字符串转到c++的string 再转为Product 类型 这是非法的。避免使用类类型隐形转换我可以在构造函数中定义explicit加以阻止。
explicit Product(string product_name = “”) : Product(product_name,product_name,0) {};

聚合类
聚合类是基本可以理解为等于JAVA的vo类或者是entity类,定义聚合类有以下几个条件:
1、所有成员都是public
2、没有定义构造函数
3、没有类内初始化
4、没有基类,也没有virtual函数
所以可以定义为这样
struct Data {
int ival;
string s;
};
所以就可以这样进行初始化使用:
Data data = {1,”TONY”}; //注意初始化列表的顺序必须和类的定义一致。

字面值常量类
由于constexpr函数必须要返回constexpr的数据,所以类类型都可以成为字面值常量类,就是说我们可以定义一个字面值常量类。要定义成为字面值常量类必须要有以下要求:
1、成员数据必须都是字面值常量类型。
2、类必须至少有一个constexpr构造函数,constexpr也可以使用=default。
3、如果一个数据成员含有类内初始值,则初始值必须是字面量表达式。同理如果是类类型初始化必须要使用类类型的constexpr构造函数。
4、类必须要使用默认析构函数。
范例如下:
class Debug {
public:
constexpr Debug(bool hw, bool io, bool other) : hw(hw), io(io), other(other) {};
private:
bool hw;
bool io;
bool other;
};

类的静态成员
类的静态成员基本与JAVA的概率一致。但是有几点需要注意:
1、静态成员函数因为没有this 所以不能在函数后面加上const
2、在类的定义外部定义静态成员函数不能重复协商static关键字
3、类的静态成员数据可以定义自身,因为静态可以定义一个不完整的类也是合法的,但是经过使用后发现,无法编译通过。
调用函数已经静态成员数据如下:
Product::getProductByClass();
Product::main_product;
声明如下:
class Product {

public:
static Product& getProductByClass();
static Product main_product;
…….
};
静态成员函数的定义:
Product& Product::getProductByClass() {
return main_product;
}

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/tony308001970/article/details/70224976

智能推荐

王斌老师的博客_王斌 github-程序员宅基地

文章浏览阅读480次。http://blog.sina.com.cn/s/blog_736d0b9101018cgc.html_王斌 github

ACM OJ Collection_htt//acm.wydtang.top/-程序员宅基地

文章浏览阅读737次。原文来自:http://blog.csdn.net/hncqp/article/details/4455263 ACM OJ Collection(排名不分先后):中国:浙江大学(ZJU):http://acm.zju.edu.cn/北京大学(PKU):htt_htt//acm.wydtang.top/

ios 自己服务器 苹果支付_修复苹果IOS支付-程序员宅基地

文章浏览阅读467次。更新记录1.0.0(2019-07-01)插件简介专门用来修复苹果IOS支付时出现"您已购买此App内购买项目。此项目将免费恢复"。问题描述首先在IOS平台里面创建“APP内购买项目”,选择的是“消耗型项目”,然后用uni-app官方的支付api进行支付,多支付几次,有时候就会出现提示“您已购买此App内购买项目。此项目将免费恢复”,特别是在沙盒测试里面支付很大几率出现,我明明选的是消耗型项目,应..._ios开发苹果支付恢复权益

spring MVC mock类单元测试(controller)_mvcmock-程序员宅基地

文章浏览阅读5.6k次。Spring从J2EE的Web端为每个关键接口提供了一个mock实现:MockHttpServletRequest几乎每个单元测试中都要使用这个类,它是J2EE Web应用程序最常用的接口HttpServletRequest的mock实现。MockHttpServletResponse此对象用于HttpServletRespons_mvcmock

【我的世界Minecraft-MC】常见及各种指令大杂烩【2022.8版】_summon生成掉落物-程序员宅基地

文章浏览阅读8.5k次,点赞7次,收藏22次。execute as @a at @s run clear @s minecraft:dark_oak_planks{display:{Name:“{“text”:“第三关[阴森古堡]”,“color”:“red”,“italic”:false}”,color:“16711680”},Enchantments:[{id:“protection”,lvl:1}],Unbreakable:1b} 1。Lore:[“{“text”:“免费”,“color”:“blue”,“italic”:false}”]..._summon生成掉落物

CentOS 7安装教程(图文详解)_centos 安装-程序员宅基地

文章浏览阅读10w+次,点赞487次,收藏2.1k次。CentOS 7安装教程: 准备: 软件:VMware Workstation 镜像文件:CentOS-7-x86_64-bin-DVD1.iso (附:教程较为详细,注释较多,故将操作的选项进行了加粗字体显示。) 1、文件--新建虚拟机--自定义 2、..._centos 安装

随便推点

Github项目分享——免费的画图工具drow,前端插件化面试_draw github画图-程序员宅基地

文章浏览阅读333次,点赞3次,收藏3次。项目介绍一款很好用的免费画图软件,支持ER图、时序图、流程图等等在项目的releases就可以下载最新版本同时支持在线编辑。_draw github画图

如何开始学习人工智能?入门的学习路径和资源是什么?_人工智能学习路径-程序员宅基地

文章浏览阅读930次。嗨,大家好!如果你对人工智能充满了好奇,并且想要入门这个领域,那么你来对地方了。本文将向你介绍如何从零基础开始学习人工智能,并逐步掌握核心概念和技能。无论你是大学生、职场新人还是对人工智能感兴趣的任何人,都可以按照以下学习路径逐步提升自己。_人工智能学习路径

Unity3D 导入资源_unity怎么导入压缩包-程序员宅基地

文章浏览阅读4.3k次,点赞2次,收藏8次。打开Unity3D的:window-asset store就会出来这样的界面:我们选择一个天空纹理,注意这里的标签只有一个,如果有多个就会显示所有标签的内容:找个比较小的免费的下载一下试试,比如这个:下载以后:点击import就会出现该窗口:然后再点击最底下的import:就导入到我们这里来了。从上面可以切换场景:..._unity怎么导入压缩包

jqgrid 服务器端验证,javascript – jqgrid服务器端错误消息/验证处理-程序员宅基地

文章浏览阅读254次。在你以前的问题的the answer的最后一部分,我试着给出你当前的问题的答案.也许我表示不够清楚.您不应该将错误信息放在标准成功响应中.您应该遵循用于服务器和客户端之间通信的HTTP协议的主要规则.根据HTTP协议实现网格中的加载数据,编辑行和与服务器的所有Ajax通信.每个HTTP响应都有响应第一行的状态代码.了解这个意义非常重要.典型的JSON数据成功请求如下HTTP/1.1 200 OK...._decode message error

白山头讲PV: 用calibre进行layout之间的比对-程序员宅基地

文章浏览阅读4k次,点赞8次,收藏29次。我们在流片之后,通常还是有机会对layout进行局部小的修改。例如metal change eco或者一些层次的局部修改。当我们修改之后,需要进行与之前gds的对比,以便确认没有因为某些..._calibre dbdiff

java exit方法_Java:如何测试调用System.exit()的方法?-程序员宅基地

文章浏览阅读694次。问题我有一些方法应该在某些输入上调用567779278。不幸的是,测试这些情况会导致JUnit终止!将方法调用放在新线程中似乎没有帮助,因为System.exit()终止了JVM,而不仅仅是当前线程。是否有任何常见的处理方式?例如,我可以将存根替换为System.exit()吗?[编辑]有问题的类实际上是一个命令行工具,我试图在JUnit中测试。也许JUnit根本不适合这份工作?建议使用互补回归测..._检查system.exit