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

智能推荐

艾美捷Epigentek DNA样品的超声能量处理方案-程序员宅基地

文章浏览阅读15次。空化气泡的大小和相应的空化能量可以通过调整完全标度的振幅水平来操纵和数字控制。通过强调超声技术中的更高通量处理和防止样品污染,Epigentek EpiSonic超声仪可以轻松集成到现有的实验室工作流程中,并且特别适合与表观遗传学和下一代应用的兼容性。Epigentek的EpiSonic已成为一种有效的剪切设备,用于在染色质免疫沉淀技术中制备染色质样品,以及用于下一代测序平台的DNA文库制备。该装置的经济性及其多重样品的能力使其成为每个实验室拥有的经济高效的工具,而不仅仅是核心设施。

11、合宙Air模块Luat开发:通过http协议获取天气信息_合宙获取天气-程序员宅基地

文章浏览阅读4.2k次,点赞3次,收藏14次。目录点击这里查看所有博文  本系列博客,理论上适用于合宙的Air202、Air268、Air720x、Air720S以及最近发布的Air720U(我还没拿到样机,应该也能支持)。  先不管支不支持,如果你用的是合宙的模块,那都不妨一试,也许会有意外收获。  我使用的是Air720SL模块,如果在其他模块上不能用,那就是底层core固件暂时还没有支持,这里的代码是没有问题的。例程仅供参考!..._合宙获取天气

EasyMesh和802.11s对比-程序员宅基地

文章浏览阅读7.7k次,点赞2次,收藏41次。1 关于meshMesh的意思是网状物,以前读书的时候,在自动化领域有传感器自组网,zigbee、蓝牙等无线方式实现各个网络节点消息通信,通过各种算法,保证整个网络中所有节点信息能经过多跳最终传递到目的地,用于数据采集。十多年过去了,在无线路由器领域又把这个mesh概念翻炒了一下,各大品牌都推出了mesh路由器,大多数是3个为一组,实现在面积较大的住宅里,增强wifi覆盖范围,智能在多热点之间切换,提升上网体验。因为节点基本上在3个以内,所以mesh的算法不必太复杂,组网形式比较简单。各厂家都自定义了组_802.11s

线程的几种状态_线程状态-程序员宅基地

文章浏览阅读5.2k次,点赞8次,收藏21次。线程的几种状态_线程状态

stack的常见用法详解_stack函数用法-程序员宅基地

文章浏览阅读4.2w次,点赞124次,收藏688次。stack翻译为栈,是STL中实现的一个后进先出的容器。要使用 stack,应先添加头文件include<stack>,并在头文件下面加上“ using namespacestd;"1. stack的定义其定义的写法和其他STL容器相同, typename可以任意基本数据类型或容器:stack<typename> name;2. stack容器内元素的访问..._stack函数用法

2018.11.16javascript课上随笔(DOM)-程序员宅基地

文章浏览阅读71次。<li> <a href = "“#”>-</a></li><li>子节点:文本节点(回车),元素节点,文本节点。不同节点树:  节点(各种类型节点)childNodes:返回子节点的所有子节点的集合,包含任何类型、元素节点(元素类型节点):child。node.getAttribute(at...

随便推点

layui.extend的一点知识 第三方模块base 路径_layui extend-程序员宅基地

文章浏览阅读3.4k次。//config的设置是全局的layui.config({ base: '/res/js/' //假设这是你存放拓展模块的根目录}).extend({ //设定模块别名 mymod: 'mymod' //如果 mymod.js 是在根目录,也可以不用设定别名 ,mod1: 'admin/mod1' //相对于上述 base 目录的子目录}); //你也可以忽略 base 设定的根目录,直接在 extend 指定路径(主要:该功能为 layui 2.2.0 新增)layui.exten_layui extend

5G云计算:5G网络的分层思想_5g分层结构-程序员宅基地

文章浏览阅读3.2k次,点赞6次,收藏13次。分层思想分层思想分层思想-1分层思想-2分层思想-2OSI七层参考模型物理层和数据链路层物理层数据链路层网络层传输层会话层表示层应用层OSI七层模型的分层结构TCP/IP协议族的组成数据封装过程数据解封装过程PDU设备与层的对应关系各层通信分层思想分层思想-1在现实生活种,我们在喝牛奶时,未必了解他的生产过程,我们所接触的或许只是从超时购买牛奶。分层思想-2平时我们在网络时也未必知道数据的传输过程我们的所考虑的就是可以传就可以,不用管他时怎么传输的分层思想-2将复杂的流程分解为几个功能_5g分层结构

基于二值化图像转GCode的单向扫描实现-程序员宅基地

文章浏览阅读191次。在激光雕刻中,单向扫描(Unidirectional Scanning)是一种雕刻技术,其中激光头只在一个方向上移动,而不是来回移动。这种移动方式主要应用于通过激光逐行扫描图像表面的过程。具体而言,单向扫描的过程通常包括以下步骤:横向移动(X轴): 激光头沿X轴方向移动到图像的一侧。纵向移动(Y轴): 激光头沿Y轴方向开始逐行移动,刻蚀图像表面。这一过程是单向的,即在每一行上激光头只在一个方向上移动。返回横向移动: 一旦一行完成,激光头返回到图像的一侧,准备进行下一行的刻蚀。

算法随笔:强连通分量-程序员宅基地

文章浏览阅读577次。强连通:在有向图G中,如果两个点u和v是互相可达的,即从u出发可以到达v,从v出发也可以到达u,则成u和v是强连通的。强连通分量:如果一个有向图G不是强连通图,那么可以把它分成躲个子图,其中每个子图的内部是强连通的,而且这些子图已经扩展到最大,不能与子图外的任一点强连通,成这样的一个“极大连通”子图是G的一个强连通分量(SCC)。强连通分量的一些性质:(1)一个点必须有出度和入度,才会与其他点强连通。(2)把一个SCC从图中挖掉,不影响其他点的强连通性。_强连通分量

Django(2)|templates模板+静态资源目录static_django templates-程序员宅基地

文章浏览阅读3.9k次,点赞5次,收藏18次。在做web开发,要给用户提供一个页面,页面包括静态页面+数据,两者结合起来就是完整的可视化的页面,django的模板系统支持这种功能,首先需要写一个静态页面,然后通过python的模板语法将数据渲染上去。1.创建一个templates目录2.配置。_django templates

linux下的GPU测试软件,Ubuntu等Linux系统显卡性能测试软件 Unigine 3D-程序员宅基地

文章浏览阅读1.7k次。Ubuntu等Linux系统显卡性能测试软件 Unigine 3DUbuntu Intel显卡驱动安装,请参考:ATI和NVIDIA显卡请在软件和更新中的附加驱动中安装。 这里推荐: 运行后,F9就可评分,已测试显卡有K2000 2GB 900+分,GT330m 1GB 340+ 分,GT620 1GB 340+ 分,四代i5核显340+ 分,还有写博客的小盒子100+ 分。relaybot@re...

推荐文章

热门文章

相关标签