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

智能推荐

JWT(Json Web Token)实现无状态登录_无状态token登录-程序员宅基地

文章浏览阅读685次。1.1.什么是有状态?有状态服务,即服务端需要记录每次会话的客户端信息,从而识别客户端身份,根据用户身份进行请求的处理,典型的设计如tomcat中的session。例如登录:用户登录后,我们把登录者的信息保存在服务端session中,并且给用户一个cookie值,记录对应的session。然后下次请求,用户携带cookie值来,我们就能识别到对应session,从而找到用户的信息。缺点是什么?服务端保存大量数据,增加服务端压力 服务端保存用户状态,无法进行水平扩展 客户端请求依赖服务.._无状态token登录

SDUT OJ逆置正整数-程序员宅基地

文章浏览阅读293次。SDUT OnlineJudge#include<iostream>using namespace std;int main(){int a,b,c,d;cin>>a;b=a%10;c=a/10%10;d=a/100%10;int key[3];key[0]=b;key[1]=c;key[2]=d;for(int i = 0;i<3;i++){ if(key[i]!=0) { cout<<key[i.

年终奖盲区_年终奖盲区表-程序员宅基地

文章浏览阅读2.2k次。年终奖采用的平均每月的收入来评定缴税级数的,速算扣除数也按照月份计算出来,但是最终减去的也是一个月的速算扣除数。为什么这么做呢,这样的收的税更多啊,年终也是一个月的收入,凭什么减去12*速算扣除数了?这个霸道(不要脸)的说法,我们只能合理避免的这些跨级的区域了,那具体是那些区域呢?可以参考下面的表格:年终奖一列标红的一对便是盲区的上下线,发放年终奖的数额一定一定要避免这个区域,不然公司多花了钱..._年终奖盲区表

matlab 提取struct结构体中某个字段所有变量的值_matlab读取struct类型数据中的值-程序员宅基地

文章浏览阅读7.5k次,点赞5次,收藏19次。matlab结构体struct字段变量值提取_matlab读取struct类型数据中的值

Android fragment的用法_android reader fragment-程序员宅基地

文章浏览阅读4.8k次。1,什么情况下使用fragment通常用来作为一个activity的用户界面的一部分例如, 一个新闻应用可以在屏幕左侧使用一个fragment来展示一个文章的列表,然后在屏幕右侧使用另一个fragment来展示一篇文章 – 2个fragment并排显示在相同的一个activity中,并且每一个fragment拥有它自己的一套生命周期回调方法,并且处理它们自己的用户输_android reader fragment

FFT of waveIn audio signals-程序员宅基地

文章浏览阅读2.8k次。FFT of waveIn audio signalsBy Aqiruse An article on using the Fast Fourier Transform on audio signals. IntroductionThe Fast Fourier Transform (FFT) allows users to view the spectrum content of _fft of wavein audio signals

随便推点

Awesome Mac:收集的非常全面好用的Mac应用程序、软件以及工具_awesomemac-程序员宅基地

文章浏览阅读5.9k次。https://jaywcjlove.github.io/awesome-mac/ 这个仓库主要是收集非常好用的Mac应用程序、软件以及工具,主要面向开发者和设计师。有这个想法是因为我最近发了一篇较为火爆的涨粉儿微信公众号文章《工具武装的前端开发工程师》,于是建了这么一个仓库,持续更新作为补充,搜集更多好用的软件工具。请Star、Pull Request或者使劲搓它 issu_awesomemac

java前端技术---jquery基础详解_简介java中jquery技术-程序员宅基地

文章浏览阅读616次。一.jquery简介 jQuery是一个快速的,简洁的javaScript库,使用户能更方便地处理HTML documents、events、实现动画效果,并且方便地为网站提供AJAX交互 jQuery 的功能概括1、html 的元素选取2、html的元素操作3、html dom遍历和修改4、js特效和动画效果5、css操作6、html事件操作7、ajax_简介java中jquery技术

Ant Design Table换滚动条的样式_ant design ::-webkit-scrollbar-corner-程序员宅基地

文章浏览阅读1.6w次,点赞5次,收藏19次。我修改的是表格的固定列滚动而产生的滚动条引用Table的组件的css文件中加入下面的样式:.ant-table-body{ &amp;amp;::-webkit-scrollbar { height: 5px; } &amp;amp;::-webkit-scrollbar-thumb { border-radius: 5px; -webkit-box..._ant design ::-webkit-scrollbar-corner

javaWeb毕设分享 健身俱乐部会员管理系统【源码+论文】-程序员宅基地

文章浏览阅读269次。基于JSP的健身俱乐部会员管理系统项目分享:见文末!

论文开题报告怎么写?_开题报告研究难点-程序员宅基地

文章浏览阅读1.8k次,点赞2次,收藏15次。同学们,是不是又到了一年一度写开题报告的时候呀?是不是还在为不知道论文的开题报告怎么写而苦恼?Take it easy!我带着倾尽我所有开题报告写作经验总结出来的最强保姆级开题报告解说来啦,一定让你脱胎换骨,顺利拿下开题报告这个高塔,你确定还不赶快点赞收藏学起来吗?_开题报告研究难点

原生JS 与 VUE获取父级、子级、兄弟节点的方法 及一些DOM对象的获取_获取子节点的路径 vue-程序员宅基地

文章浏览阅读6k次,点赞4次,收藏17次。原生先获取对象var a = document.getElementById("dom");vue先添加ref <div class="" ref="divBox">获取对象let a = this.$refs.divBox获取父、子、兄弟节点方法var b = a.childNodes; 获取a的全部子节点 var c = a.parentNode; 获取a的父节点var d = a.nextSbiling; 获取a的下一个兄弟节点 var e = a.previ_获取子节点的路径 vue