由于下一講要講到怎么在類中pub和sub消息.那么考慮到有些同學(xué)對(duì)類不甚熟悉.我們稍微回顧一下.但關(guān)于類網(wǎng)上一查其實(shí)一大堆東西,而且都是從入門(mén)講起.所以我這兒肯定不會(huì)重復(fù)書(shū)寫(xiě)那些內(nèi)容.要介紹的幾個(gè)東西扯罐,其實(shí)本來(lái)要用得好的話蠻復(fù)雜负拟,我們只會(huì)涉及到皮毛,重心會(huì)放在和之前的代碼比較歹河,以了解之前我們之前三講的很多語(yǔ)法為什么可以那么寫(xiě).
比如上一講的geometry_msgs::PoseStamped的對(duì)象msg包含成員變量header和pose掩浙,heaer包含成員變量stamp等,為什么我們就可以使用msg.header.stamp
這種語(yǔ)法來(lái)獲取類型為time的變量秸歧?
再比如std_msgs::Int8這種語(yǔ)法怎么來(lái)的厨姚,中間那個(gè)::表示什么意思,以及它前后的std_msgs和In8有什么區(qū)別.
再比如我們定義ROS publisher時(shí)
ros::Publisher chatter_pub = n.advertise<std_msgs::String>("chatter", 1000);
為什么通過(guò)<std_msgs::String>
這種語(yǔ)法來(lái)定義要發(fā)送的對(duì)象键菱?
這三個(gè)比如分別涉及到類谬墙,命名空間和模版.對(duì)語(yǔ)法熟悉或者不想究其所以然的同學(xué)可以跳過(guò)這一章直接進(jìn)入下一章的講在類中pub和sub消息.
這一講假設(shè)大家對(duì)函數(shù),參數(shù)经备,循環(huán)等最基本的C++的東西已經(jīng)掌握了.如果這些不清楚那么用C++操作ROS確實(shí)不太合適哈哈.
類(class)
同樣類的作用和意義我就不詳細(xì)闡釋了拭抬,網(wǎng)上一抓一大把,他們的基本意義大家可以上網(wǎng)搜索.簡(jiǎn)單來(lái)講侵蒙,定義了類之后我們可以創(chuàng)建它的對(duì)象.對(duì)類和其對(duì)象直接操作是c++最重要的東西之一.直接開(kāi)始例子.打開(kāi)一個(gè)terminal造虎,輸入下面的內(nèi)容
mkdir ~/C++Test
cd C++Test
mkdir classTest
mkdir namespaceTest
mkdir templateTest
咱們創(chuàng)建一個(gè)叫C++Test的文件夾,再創(chuàng)建三個(gè)用于測(cè)試三種東西的子文件夾.之后蘑志,在classTest文件夾下創(chuàng)建一個(gè)叫classBasic.cpp
的文件和一個(gè)叫CMakeLists.txt
的文件.在classBasic.cpp中輸入下面內(nèi)容.
#include <iostream>
class poorPhd{
public:
/*define constructor*/
poorPhd(){
std::cout<<"we create a poor phd class"<<std::endl;
}
/*public member variable*/
int hairNumber = 100;
/*public member function*/
int getGirlFriendNumber(){
return girlFriendNumber;
}
private:
/*private member variable*/
int girlFriendNumber = 0;
};
int main(){
/*define the object*/
poorPhd phd;//will use constructor function
/*call the public memberfunction*/
std::cout<<"girlFriendnNumber is "<<phd.getGirlFriendNumber()<<std::endl;
/*change tha value of member variale*/
phd.hairNumber = 101;
/*call the member variable*/
std::cout<<"hairNumber is "<<phd.hairNumber<<std::endl;
/*define class pointer*/
poorPhd *phdPointer;
/*assign the pointer to an object*/
phdPointer = &phd;
/*call the member variable*/
std::cout<<"use pointer, hair number is "<<phdPointer->hairNumber<<std::endl;
}
逐行解說(shuō).
1:#include<> 包含頭文件累奈,這樣可以使用std::cout<<...std::endl;
2:class poorPhd 定義了一個(gè)叫poorPhd的類.類后跟這宗括號(hào){}.宗括號(hào)中的內(nèi)容為類的內(nèi)容.
3:public 加冒號(hào)之后的內(nèi)容贬派,即為公有
.公有范圍內(nèi)定義的函數(shù)為公有成員函數(shù),變量為公有成員變量.
4:poorPhd(). 這個(gè)函數(shù)稱為構(gòu)造函數(shù)(constructor function)
.在類創(chuàng)建時(shí)澎媒,會(huì)自動(dòng)調(diào)用.構(gòu)造函數(shù)的名字和類的名字必須一樣并且沒(méi)有返回值.
5:int hairNumber = 100. 定義了一個(gè)int類型公有成員變量搞乏,賦值100.
6:int getGirlFriendNumber(). 定義了一個(gè)返回值為int的函數(shù),該函數(shù)會(huì)返回私有成員變量girlFriendNumber.
7:private加冒號(hào)之后的內(nèi)容戒努,即為私有
.私有范圍內(nèi)定義的函數(shù)為私有成員函數(shù)请敦,變量為私有成員變量.
8: int girlFriendNumnber=0. 定義了一個(gè)int類型的私有成員變量girlFriendNumber
并賦值為0
main函數(shù)中
9: poorPhd phd 創(chuàng)建了一個(gè)類的對(duì)象(object),名字叫phd
.每一個(gè)類储玫,要想實(shí)際被使用侍筛,都需要?jiǎng)?chuàng)建一個(gè)對(duì)象.對(duì)象會(huì)擁有之前我們?cè)陬愔卸x的所有東西.所謂擁有,即是可以調(diào)用他們.對(duì)象的數(shù)量是沒(méi)有限制的撒穷,并且他們之間不會(huì)干擾.你還可以用類似方法創(chuàng)建一個(gè)名字加abc
的對(duì)象匣椰,它也會(huì)擁有poorPhd這個(gè)類的全部東西.
對(duì)象在創(chuàng)建時(shí),會(huì)自動(dòng)調(diào)用構(gòu)造函數(shù).
10:std::cout....phd.getGirlFriendNumber()<<std::endl;
類對(duì)象調(diào)用成員函數(shù)或者成員變量的方法是對(duì)象名.成員
.公有成員可以在類的定義外使用這種方式直接調(diào)用端礼,私有成員是不可以被直接調(diào)用的.所以如果我們使用phd.girlFriendNumber
就會(huì)報(bào)錯(cuò).因?yàn)樵陬愅馇菪Γ豢梢灾苯诱{(diào)用私有成員變量.那有時(shí)候我們?nèi)匀幌肟吹交蛘咝薷乃接谐蓡T變量怎么辦呢?那么我們可以寫(xiě)類似于這個(gè)gerGirlFriend
的公有成員函數(shù).公有成員函數(shù)定義在類中蛤奥,所以它可以使用私有成員變量佳镜,并把變量的值作為返回值,這樣我們就得到可私有成員變量的值.
為什么要分私有公有呢凡桥?有時(shí)候我們寫(xiě)了一個(gè)類蟀伸,并不想其中所有東西都被使用者使用,比如我們有了造車相關(guān)技術(shù)缅刽,所有這些技術(shù)和在一起啊掏,就是類.具體實(shí)現(xiàn),就是我們?cè)炝艘惠v輛車子.每一輛車子就稱為對(duì)象.每一輛車子都有相同的內(nèi)容拷恨,但是他們互不干擾.我們只想用戶了解剎車脖律,油門(mén)等東西.并不想用戶了解車子內(nèi)部構(gòu)造.那剎車油門(mén)在這兒就是公有,而車子內(nèi)部構(gòu)造就是私有.如果用戶實(shí)在想獲取內(nèi)部構(gòu)造腕侄,用戶可以去汽車銷售店了解些相關(guān)資料小泉,銷售店就相當(dāng)于咱們寫(xiě)的那個(gè)get...
函數(shù)接口,架起用戶和類私有成員友誼的橋梁.當(dāng)然冕杠,如果有些內(nèi)容特別私密微姊,我們并不想用戶了解它的相關(guān)資料,就不寫(xiě)那個(gè)get...
函數(shù)就行了.
- phd.hairNumber = 101;
為公有成員變量賦值101.
12.std::cout<<...phd.hairNumber...
調(diào)用公有成員并print出來(lái).
13.poorPhd *phdPointer
創(chuàng)建一個(gè)類的指針.類的指針被創(chuàng)建時(shí)不會(huì)調(diào)用構(gòu)造函數(shù).它需要指向一個(gè)對(duì)象.
14.phdPointer = &phd
剛才創(chuàng)建的對(duì)象的地址賦值給指針分预,這個(gè)指針就有了phd
對(duì)象的所有內(nèi)容.
-
...phdPointer->hairNumber...
類指針調(diào)用類的成員的唯一不同之處就是使用指針名->成員
調(diào)用而不是對(duì)象名.成員
調(diào)用.
和之前寫(xiě)的ROS代碼的聯(lián)系: 之前我們定義過(guò)std_msgs::Int8 msg
兢交,msg即是類Int8的對(duì)象.我們通過(guò)查看roswiki http://docs.ros.org/api/std_msgs/html/msg/Int8.html 得知Int8包含類型為int8的成員變量data,所以我們通過(guò)msg.data
使用這個(gè)成員.
寫(xiě)好文件后退出保存笼痹,打開(kāi)之前建立的CMakeLists.txt文件.輸入以下內(nèi)容.
project(class_test)
cmake_minimum_required(VERSION 2.8)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAG} -std=c++11 -Wall")
add_executable(classBasic classBasic.cpp)
這基本上算是一個(gè)最簡(jiǎn)單的CMakeLists.txt文件了.CMakeLists.txt是用來(lái)編譯C++文件的.
第一行表明了項(xiàng)目名稱.
第二行輸入CMake使用的最小版本號(hào)配喳,一般是2.8以及以上.
第三行設(shè)定編譯器.使用c++11.雖然我們的項(xiàng)目沒(méi)用到c++11但是考慮到如今c++已經(jīng)被普遍使用了酪穿,所以最好加上.我們?cè)赗OS的CMakeLists里注釋過(guò)這個(gè)內(nèi)容add_compile_options(-std=c++11)
達(dá)到的也是使用c++11編譯的效果.
第四行指定要編譯的文件.要編譯的文件是classBasic.cpp,編譯后的可執(zhí)行文件名字叫classBasic.
寫(xiě)完上面的內(nèi)容后晴裹,保存退出.
在terminal中cd 到classTest
這個(gè)文件夾輸入下面的內(nèi)容
mkdir build
cd build
cmake ..
make
第一二行命令創(chuàng)建一個(gè)叫build的文件夾并進(jìn)入
第三行命令使用是使用cmake命令并通過(guò)..
表示使用上一個(gè)文件夾的CMakeLists.txt.執(zhí)行這行命令之后我們寫(xiě)的CMakeLists就會(huì)產(chǎn)生一系列的文件在build中被济,其中一個(gè)是Makefile.其他的這里不作介紹
第四行命令是使用makefile.makefile的作用就是直接編譯你在CMakeLists里設(shè)定好的文件了.
建立一個(gè)build文件夾不是必須的但是推薦,因?yàn)槟憧吹絙uild里有一系列編譯CMakeLists.txt里產(chǎn)生的文件涧团,你以后要?jiǎng)h除或者修改他們會(huì)比較方便只磷,不至于和其他文件混在一起.
執(zhí)行完上面的命令后,你會(huì)看到多了一個(gè)叫classBasic
的文件沒(méi)有后綴泌绣,這就是我們的可執(zhí)行二進(jìn)制文件了.使用./classBasic
執(zhí)行后得到下面的輸出
we create a poor phd class
girlFriendnNumber is 0
hairNumber is 101
use pointer, hair number is 101
請(qǐng)對(duì)應(yīng)源代碼一行行查看輸出為何如此.
上一章我們說(shuō)過(guò)有這樣一段話msgs_header.stamp調(diào)用stamp钮追,stamp.sec調(diào)用sec得到epoch的時(shí)間,那么msgs_header.stamp.sec就可以獲取當(dāng)前的時(shí)間阿迈,秒為單位.寫(xiě)段話之前我們創(chuàng)建了Header的對(duì)象msg_header元媚,并通過(guò)ros wiki知道了該對(duì)象包含數(shù)據(jù)成員stamp,stamp包含數(shù)據(jù)成員sec苗沧,然后我們我們可以用這種msg_header.stamp.sec
來(lái)調(diào)用sec這個(gè)數(shù)據(jù)成員.這種數(shù)據(jù)之間看起來(lái)的連續(xù)性具體是怎么實(shí)現(xiàn)的呢惠毁?
咱們?cè)谥皠?chuàng)建的classTest文件夾下再創(chuàng)建一個(gè)新的文件叫 classBasic2.cpp.并輸入下面的內(nèi)容.
#include <iostream>
class poorPhd{
public:
/*define constructor*/
poorPhd(){
std::cout<<"we create a poor phd class"<<std::endl;
}
/*public member variable*/
int hairNumber = 100;
/*public member function*/
int getGirlFriendNumber(){
return girlFriendNumber;
}
private:
/*private member variable*/
int girlFriendNumber = 0;
};
class master1 {
public:
/*define constructor*/
master1(){
std::cout<<"we create a master class"<<std::endl;
}
/*member variable*/
poorPhd future;
};
int main(){
/*define the object*/
master1 mStudent1;
/*use inheritance*/
std::cout<<"hairNumber of master student 1 is "<<mStudent1.future.hairNumber<<std::endl;
}
poorPhd
類和上一個(gè)文件完全一樣,我們新添加了一個(gè)類叫master1
.master1同樣有一個(gè)構(gòu)造函數(shù).另外它有一個(gè)成員變量崎页,這個(gè)成員變量是poorPhd類型的對(duì)象future.那么在main函數(shù)中,定義了master1的對(duì)象mStudent1.咱們就可以用mStudent1.future調(diào)用變量future腰埂,再由于future是poorPhd類型的變量飒焦,所以可以用future.hairNumber調(diào)用hairNumber.連在一起就可以通過(guò)定義msater1的對(duì)象卻最終調(diào)用了poorPhd的成員變量了.
保存退出后,在CMakeLists.txt中添加下面的內(nèi)容.
add_executable(classBasic2 classBasic2.cpp)
terminal中進(jìn)入classTest/build文件加輸入
cmake ..
make
這時(shí)候就多了一個(gè)二進(jìn)制文件classBasic2屿笼,執(zhí)行該二進(jìn)制文件你會(huì)看到
we create a poor phd class
we create a master class
hairNumber of master student 1 is 100
從這個(gè)輸入可以看出牺荠,創(chuàng)建master1的對(duì)象mStudent1的時(shí)候c++會(huì)首先初始化它的成員變量,所以咱們先得到的是create a poor phd class驴一,之后再調(diào)用了構(gòu)造函數(shù).
類還有很多很多的內(nèi)容休雌,就靠大家自己取學(xué)習(xí)了,咱們這兒只是簡(jiǎn)單地介紹了和前面的代碼聯(lián)系的部分.
命名空間(namespace)
你肯定使用過(guò)命名空間肝断,基本上每一個(gè)寫(xiě)c++的人都會(huì)用過(guò)using namespace std
這條語(yǔ)句.這條語(yǔ)句代表使用命名空間std.達(dá)到的效果是杈曲,例如你要使用cout
語(yǔ)句在屏幕上打印什么東西,如果沒(méi)有std胸懈,你需要輸入的是
std::cout<<"....."<<std::endl;
如果你使用了using namespace std這條語(yǔ)句担扑,那么你就只需要下面的內(nèi)容打印語(yǔ)句
cout<<"...."<<endl;
但是你如果沒(méi)寫(xiě)過(guò)大型程序的話,可能沒(méi)有機(jī)會(huì)自己寫(xiě)過(guò)命名空間.命名空間一般是用來(lái)避免重命名的.大型的庫(kù)里面一般定義了很多類趣钱,無(wú)數(shù)的函數(shù).不同的大型的庫(kù)之間很可能會(huì)有函數(shù)甚至類的命名重復(fù)涌献,這會(huì)造成很大的麻煩.
namespace的命名語(yǔ)法也很簡(jiǎn)單
namespace name{
//內(nèi)容
}
下面這個(gè)程序簡(jiǎn)單地展示了兩個(gè)命名空間里定義相同名字的類,并分別使用兩個(gè)類的簡(jiǎn)單程序.
#include <iostream>
/*define a phd namespace*/
namespace phd {
/*define a student class in phd namespace*/
class student{
public:
student(){
std::cout<<"create a student class in phd namespace"<<std::endl;
}
int graduateYear = 5;
int hairNumber = 100;
};
}
/*define a master namespace*/
namespace master{
/*define a student class in master namespace*/
class student{
public:
student(){
std::cout<<"create a student class in master namespace"<<std::endl;
}
int graduateYear = 2;
int hairNumber = 10000;
};
}
int main(){
/*create an object of student class, in phd namespace*/
phd::student phdStudent;
/*create an object of student class, in master namespace*/
master::student masterStudent;
std::cout<<"phd normally graduate in "<<phdStudent.graduateYear<<" years"<<std::endl;
std::cout<<"master normally graduate in "<<masterStudent.graduateYear<<" years"<<std::endl;
}
上面的這個(gè)程序定義了兩個(gè)命名空間首有,一個(gè)叫phd
燕垃,一個(gè)叫master
枢劝,這兩個(gè)命名空間擁有一個(gè)類,類名都叫student
.
定義命名空間中的類的對(duì)象的方法是命名空間名::類名 對(duì)象名
.::
被稱為作用域符號(hào)(scope resolution operator).在main函數(shù)中我們定義了phd命名空間下的student類的對(duì)象phdStudent和master命名空間下的類student的對(duì)象masterStudenrt. 后面的兩行各自輸出了成員變量graduateYear
.
在我們之前的ros程序中卜壕,遇到了兩個(gè)命名空間您旁,一個(gè)是std_msgs
,另一個(gè)是geometry_msgs
.Int8, Float64
等都是std_msgs這個(gè)命名空間下的類印叁,PoseStamped
等是geometry_msgs這個(gè)命名空間下的類.
回到上面的程序我們?cè)诙x完phd這個(gè)命名空間后被冒,可以使用using namespace phd
,這樣在main函數(shù)中我們可以不使用phd::
來(lái)定義一個(gè)phd下的student類的對(duì)象,直接student phdStudent
即可.同樣轮蜕,如果我們添加using namespace master
昨悼,我們也可以直接使用student masterStudent
來(lái)定義msater命名空間下student類的對(duì)象.
但是如果在程序中同時(shí)添加了
using namespace phd;
using namespace master;
這時(shí)候你在main函數(shù)中寫(xiě)student object_name
就肯定會(huì)報(bào)錯(cuò).因?yàn)殡娔X無(wú)法知道你要使用的student類是屬于哪個(gè)命名空間的.所以一般為了圖方便,在我們確定沒(méi)有類名會(huì)重復(fù)時(shí)跃洛,我們添加using namespace ...
這一行在定義完頭文件之后率触,這樣我們就可以省去在定義類時(shí)一直使用namespace_name::類名
這種格式命名.但是有些時(shí)候如果兩個(gè)庫(kù)很有可能有相同的類名,就不要使用using namespace ...
汇竭,不然很有可能造成程序的誤解.
寫(xiě)好上面的程序后和咱們寫(xiě)classBasic.cpp的過(guò)程完全一樣的步驟葱蝗,創(chuàng)建CMakeLists.txt和一個(gè)build文件夾進(jìn)行編譯.
可能有的讀者會(huì)問(wèn)那如果命名空間的名字都重復(fù)了呢?你就刪掉其中一個(gè)程序把 = = ....
同樣细燎,命名空間有的是學(xué)問(wèn)两曼,有興趣的同學(xué)自行研究.
模版(Template)
模版這個(gè)東西,你如果是c++的使用者玻驻,那必定也接觸過(guò).為什么這么說(shuō)呢悼凑?當(dāng)你定義一個(gè)std::vector的時(shí)候,你就已經(jīng)使用了模版了.但是你可能沒(méi)自己寫(xiě)過(guò)模版(這種情況好像和namespace有點(diǎn)相似).
模版是為了避免重復(fù)定義同樣功能的函數(shù)而開(kāi)發(fā)的.
打個(gè)比方璧瞬,你現(xiàn)在要實(shí)現(xiàn)平方一個(gè)數(shù)的函數(shù).很簡(jiǎn)單户辫,類似于下面這樣
#include <iostream>
int square(int a){
return a*a;
}
int main(){
double x = 5.3;
std::cout<<"the square of "<<x <<" is "<<square(x)<<std::endl;
}
這個(gè)程序有個(gè)很明顯的缺點(diǎn),編寫(xiě)函數(shù)或者使用變量時(shí)嗤锉,都必須先指定類型渔欢,由于c++函數(shù)形參類型和返回值已經(jīng)指定為int類型了,你只能傳int類型進(jìn)去瘟忱,如果傳double類型的變量進(jìn)去奥额,變量會(huì)被強(qiáng)制轉(zhuǎn)換截?cái)酁閕nt類型.而且只能return整型的變量.所以你只能得到25.
基本的解決方法是函數(shù)的重載,即我可以命名相同的函數(shù)但是變量類型或者個(gè)數(shù)不同以實(shí)現(xiàn)對(duì)不同輸入的處理.類似于下面這樣
#include <iostream>
int square(int a){
return a*a;
}
double suqare(double a ){
return a*a;
}
int main(){
double x = 5.3;
std::cout<<"the square of "<<x <<" is "<<square(x)<<std::endl;
}
這樣調(diào)用square(x)時(shí)會(huì)自動(dòng)匹配形參相同的函數(shù).我們可以得到5.3的平方.但是可以想象酷誓,如果我有很多不同類型的變量要傳入披坏,我就得寫(xiě)好多不同的除了變量類型不同,其他的一模一樣的函數(shù)了盐数!有沒(méi)有一種方法棒拂,形參什么類型都是可以的呢?
模版應(yīng)運(yùn)而生.模版的定義方式是
template <typename T>
或者
template <class T>
定義完之后后面緊跟要實(shí)現(xiàn)的函數(shù)或者是類.這個(gè)class不是我們之前理解的那種class了.這兒的class和typename作用完全一樣,表示定義了一個(gè)新的類型T.這個(gè)新的類型具體是什么不知道帚屉,要等我們具體使用時(shí)程序根據(jù)傳入的類型自行判斷.
咱們先上代碼谜诫,實(shí)現(xiàn)數(shù)字平方相同的功能.
#include <iostream>
template <typename T>
T square(T a){
return a*a;
}
int main(){
double x = 5.3;
std::cout<<"square of "<<x<<" is "<<square(x)<<std::endl;
}
現(xiàn)在你無(wú)論傳什么類型的數(shù)據(jù)進(jìn)去,都會(huì)得到它的平方.sqaure指定的函數(shù)形參和返回值類型都為T(mén).可以這樣理解攻旦,現(xiàn)在當(dāng)我們傳入一個(gè)double類型的變量時(shí)喻旷,T就會(huì)自動(dòng)變成double,傳入int時(shí)牢屋,T就自動(dòng)變?yōu)閕nt.
下面來(lái)一個(gè)稍微復(fù)雜一點(diǎn)的例子的.實(shí)現(xiàn)兩個(gè)向量的相加(好像也不怎么復(fù)雜...). 向量在c++里是不能直接相加的.我們定義向量時(shí)要指定向量元素的類型.比如std::vector<int> a
且预,std::vector<double> b
等.和上一個(gè)例子一樣,為了避免傳入重載函數(shù)烙无,我們使用模版.代碼如下
#include <iostream>
#include <vector>
template <typename T, typename U>
U addVector(T vec1, U vec2){
U result;
if(vec1.size()!=vec2.size()){
std::cout<<"cannot add two vector, they must be the same length. Return a null vector"<<std::endl;
return result;
}
for(int i = 0; i<vec1.size(); i++){
result.push_back(vec1[i]+vec2[i]);
}
return result;
}
int main(){
std::vector<int> vec1 = {1,2,3};
std::vector<double> vec2 = {4.0,5.0,6.0};
auto addVec = addVector(vec1,vec2);
for(auto i:addVec)
std::cout<<i<<",";
std::cout<<std::endl;
}
我們的tempalte定義了兩個(gè)類型锋谐,一個(gè)叫U,一個(gè)叫T.為什么要定義兩個(gè)呢截酷?因?yàn)榍懊嬲f(shuō)過(guò)模板定義的具體類型在使用時(shí)確定的涮拗,在主函數(shù)中我們要加兩個(gè)vector,一個(gè)是int類型的,作為第一個(gè)參數(shù)傳入addVector迂苛,那么T就會(huì)是std::vector<int>
三热,而第二個(gè)參數(shù)是double類型的向量,作為第二個(gè)參數(shù)傳入函數(shù)后U就會(huì)相當(dāng)于std::vector<double>
三幻,函數(shù)返回的類型也是U.
程序主函數(shù)第三行使用了auto
這個(gè)關(guān)鍵字.使用c++11編譯才可使用auto.這個(gè)是很有用的關(guān)鍵字.a(chǎn)uto會(huì)自動(dòng)分配被它定義的對(duì)象的類型就漾,根據(jù)賦值的變量的類型.a(chǎn)ddVector返回的是U,在這個(gè)程序里也就是std::vector<double>了.那么auto會(huì)自動(dòng)讓addVec稱為dpuble類型的vector.
主函數(shù)第四行的for循環(huán)采用的是有別于我們常用的for循環(huán)的形式.
for(auto i:addVec)
其中i:addVec
的作用是把a(bǔ)ddVec中的元素依次賦值給i念搬,這就要求i的類型得和addVec中的元素的類型相同从藤,不過(guò)有auto的幫助,我們也就不用管這么多了锁蠕,把i的類型定義為auto,那么程序會(huì)自動(dòng)讓i成為addVec中要賦值給i的元素的類型懊蒸,這兒也就是double了.
說(shuō)了這么多荣倾,還沒(méi)到我們最初想講的,那就是類似于std::vector<int>
和我們使用ros的時(shí)候定義的advertise<std_msgs::String>
這種類型的語(yǔ)法是怎么來(lái)的骑丸?首先根據(jù)命名空間那兒的學(xué)習(xí)我們知道std肯定是代表命名空間的名字了舌仍,vector是一個(gè)類,而<int>則來(lái)源于模版.如果我們使用模版定義了一個(gè)類通危,則會(huì)出現(xiàn)類似的內(nèi)容.還是用簡(jiǎn)單的square函數(shù)來(lái)舉例.我們來(lái)建立一個(gè)簡(jiǎn)單的sqaure類.
#include <iostream>
template <typename T>
class square{
public:
T a;
/*constructor function will store _a*_a as public member a*/
square(T _a){
a = _a*_a;
}
};
int main(){
double x = 5.5;
square<double> test(x);
std::cout<<"the square of "<<x<<" is "<<test.a<<std::endl;
}
在聲明了模版之后緊接著我們聲明了一個(gè)類铸豁,類的公有成員函數(shù)是一個(gè)類型為T(mén)的值a.主函數(shù)中,在我們聲明模版下定義的類的對(duì)象時(shí)菊碟,我們需要在<>
之中表明T的類型.再這之后才能定義對(duì)象.即普通的類的對(duì)象的定義格式如下
類名 對(duì)象名(構(gòu)造函數(shù)參數(shù))
模版下的類的對(duì)象定義的格式就是
類名<模版變量類型> 對(duì)象名(構(gòu)造函數(shù)參數(shù))
main函數(shù)第二行的這種定義方法节芥,就類似于我們std::vector<int> ABC
這種定義方法了,后者多的不過(guò)是在命名空間下定義了模版.然后再在模版下定義類.
總結(jié)
這一講我們粗略地涉及到c++中幾個(gè)簡(jiǎn)單又龐雜的系統(tǒng),類头镊,命名空間和模版蚣驼,在我們平常使用的語(yǔ)法中多多少少都出現(xiàn)過(guò)他們的影子.只是我們自己不經(jīng)常定義罷了.學(xué)會(huì)使用他們對(duì)建立龐雜的代碼系統(tǒng)很有幫助.我們還介紹了最簡(jiǎn)要的CMakeLists的需要包含的內(nèi)容.下一講咱們回到ROS.在這一講的基礎(chǔ)之上,講解在ros的類中發(fā)布/接收消息