機(jī)器人操作系統(tǒng)ROS:從入門(mén)到放棄(四) C++類,命名空間饮戳,模版豪治,CMakeLists介紹

由于下一講要講到怎么在類中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ù)就行了.

  1. 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)容.

  1. ...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_msgsInt8, 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ā)布/接收消息

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末相艇,一起剝皮案震驚了整個(gè)濱河市颖杏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌坛芽,老刑警劉巖留储,帶你破解...
    沈念sama閱讀 211,265評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異咙轩,居然都是意外死亡获讳,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,078評(píng)論 2 385
  • 文/潘曉璐 我一進(jìn)店門(mén)臭墨,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)赔嚎,“玉大人,你說(shuō)我怎么就攤上這事胧弛∮任螅” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,852評(píng)論 0 347
  • 文/不壞的土叔 我叫張陵结缚,是天一觀的道長(zhǎng)损晤。 經(jīng)常有香客問(wèn)我,道長(zhǎng)红竭,這世上最難降的妖魔是什么尤勋? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,408評(píng)論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮茵宪,結(jié)果婚禮上最冰,老公的妹妹穿的比我還像新娘。我一直安慰自己稀火,他們只是感情好暖哨,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,445評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著凰狞,像睡著了一般篇裁。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上赡若,一...
    開(kāi)封第一講書(shū)人閱讀 49,772評(píng)論 1 290
  • 那天达布,我揣著相機(jī)與錄音,去河邊找鬼逾冬。 笑死黍聂,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播分冈,決...
    沈念sama閱讀 38,921評(píng)論 3 406
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼圾另,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了雕沉?” 一聲冷哼從身側(cè)響起集乔,我...
    開(kāi)封第一講書(shū)人閱讀 37,688評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坡椒,沒(méi)想到半個(gè)月后扰路,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,130評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡倔叼,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,467評(píng)論 2 325
  • 正文 我和宋清朗相戀三年汗唱,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片丈攒。...
    茶點(diǎn)故事閱讀 38,617評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡哩罪,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出巡验,到底是詐尸還是另有隱情际插,我是刑警寧澤,帶...
    沈念sama閱讀 34,276評(píng)論 4 329
  • 正文 年R本政府宣布显设,位于F島的核電站框弛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏捕捂。R本人自食惡果不足惜瑟枫,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,882評(píng)論 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望指攒。 院中可真熱鬧慷妙,春花似錦、人聲如沸允悦。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,740評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)澡屡。三九已至,卻和暖如春咐旧,著一層夾襖步出監(jiān)牢的瞬間驶鹉,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,967評(píng)論 1 265
  • 我被黑心中介騙來(lái)泰國(guó)打工铣墨, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留室埋,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,315評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像姚淆,于是被迫代替她去往敵國(guó)和親孕蝉。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,486評(píng)論 2 348

推薦閱讀更多精彩內(nèi)容