使用本地c/c++提高iOS性能 之四

c++编程
c++


c++是c的超集,因此这里你将会学到更多的技术。和Objective-C相比,c++有不少不一样的概念和语法,尽管他们都是面向对象的编程语言。他们有不少重要的不一样之处:类,指针,多重继承,内存管理,和模板。sql


class类数据库


这点和Objective-C相似,一个类有两个文件:一个是头文件,另外一个是实现文件。你一样能够指定private和public的成员或方法。下面是声明一个类的头文件的标准方式:编程


class Cat {  编程语言

   public:
ide

           // public accessors
           unsigned int GetAge();
           void SetAge(unsigned int Age);
函数

           Cat ();
           Cat (int initialAge);~Cat();
性能

           // public member functions学习

           void Meow();ui


           // private member data

   private:

           unsigned int itsAge;

};


// GetAge, Public accessor function

// returns value of itsAge member

unsigned int Cat::GetAge() {

       return itsAge;

}


// returns sets itsAge member
void Cat::SetAge(unsigned int age) {

       // set member variable its age to

       // value passed in by parameter age

       itsAge = age;

}


// action: Prints "meow" to screen

void Cat::Meow() {

       cout << "Meow.\n";

}


int main() {  

   Cat cat;

   cat.Meow();

}


你能够看到,public和private声明能够分开放在不一样地方,就像Objective-C中定义头文件时使用的修饰符@private和@public。对于类的实现,你须要在方法的前面加上类的名称,来代表方法是属于这个类的。


对于访问和设置方法,你须要显示的声明他们:


unsigned int GetAge();
void SetAge(unsigned int Age);


为了建立一个Cat对象,你只须要声明Cat cat;而后调用方法cat.Meow();可是对象只存在函数的局部范围内部。


对于内存管理,你须要同时声明构造函数和析构函数。若是没有声明你本身的构造函数,编译器会使用一个没有参数的默认构造函数。



注意:若是声明了本身的构造函数,请记住也要声明析构函数,即便它没有作什么事情。遵照这个预约是很是好的。若是使用Cat cat建立Cat的一个新对象,你须要一个默认构造函数。




指针和内存管理


若是你想要在程序其余地方使用你新建立的对象,在c++中,你须要在自由存储区中申请分配内存。这个对象会一直存在,直到你显示的在内存中把它删除,就像c语言同样。为了声明指向一个包含整型值的内存地址指针,你能够像这样:


int *pInt;
pInt = new int;

*pInt = 72;


分配和释放一个对象,你可使用new和delete关键字。


Cat *pCat = new Cat;

pCat->SetAge(5);

delete pCat;
pCat = 0;



注意:若是你delete同一个指针两次,你的应用会崩溃。若是你在从新分配以前没有delete它,会有内存泄露。




继承


相比于Objective-C,c++继承的概念更加复杂。你能够像正常同样使用继承,复写,多态。惟一不一样的是virtual和pure virtual方法。


class Dog : Mammal {

}


Dog类继承了Mammal类的全部属性和方法,同时它可以有本身的属性和方法。当Dog对象被建立的时候,Mammal的构造函数先调用,而后在调用Dog的构造函数。


c++继承中有一个很是重要的概念:你只可以复写virtual方法。对于其余方法,你只能继承而不能复写。在父类和子类中能够有两个同名的方法,可是不存在复写和多态。对于virtual方法,建议在必要的时候在子类中进行复写。c++中方法默认的修饰符是非virtual的。有两种类型的虚函数:虚函数和纯虚函数。


#include "stdafx.h"

#include "stdio.h"

using namespace System;

class Animal {

   public:

           virtual void Speak() = 0;

           virtual void Eat();
           void Run();

};

void Animal::Eat(){

       printf("Animal eats\n");

}

void Animal::Run(){

   printf("Animal runs\n");

}


class Dog : Animal{
   public:

           void Eat();

           void Speak();

           void Run();

};

void Dog::Eat(){

       printf("Dog eats\n");

}

void Dog::Run(){

       printf("Dog runs\n");

}

void Dog::Speak(){

   printf("Dog speaks\n");

}

int main(){

   Animal *dog1 = (Animal *) new Dog;

   dog1->Run();

   dog1->Speak();

   dog1->Eat();

   getchar();

}


对于虚函数,在父类中你能够有它的实现;可是对于纯虚函数,你只能声明。Eat方法是虚函数,而Speak是纯虚函数。在子类中,这两个方法都须要复写。


由于Run不是虚函数,子类不须要复写。所以main函数的输出将是


Animal Runs

Dog Speaks

Dog Eats



多重继承


在c++中,你的类能够继承不少父类,所以你可以重用更多的属性和方法。例如,Teacher类同时继承Employee和Person类,如如9-4。


你能够经过下面这样进行多重继承


class Teacher : public Person, public Employee {

}


多重继承存在一个广泛的问题:当两个父类有相同的方法时。例如,Pesron和Employee两个类都声明了GetIncome方法。所以,当你在Teacher对象中调用此方法时,你必须显示的指定是调用哪一个父类的方法。


若是你只是这样写


int currentIncome = pTeacherGetIncome();


你会获得一个编译错误


Member is ambiguous: ‘Person::GetIncome’ and ‘Employee::GetIncome’


你须要显示的指明调用哪一个父类的函数来消除这个二义性。


int currentIncome = pTeacherEmployee::GetIncome();



模板


在c++中,你能够定义类或方法只接收某种指定的类型。例如,你能够定义一个方法,只接收两个同类型的参数进行比较而后返回结果。


template <class T>
T GetMax (T a, T b) {

   return (a>b)? a : b;

}

int main () {
   int i=5, j=6, k;

   long l=10, m=5, n;

   k=GetMax<int>(i,j);

   n=GetMax<long>(l,m);

   return 0;

}


经过定义一个模板方法,你能够确保a和b是一样的数据类型,这样他们就能够进行比较。你能够在类中也进行一样的操做。


template <class T>

class mypair {

      T a, b;

       public:

               mypair (T first, T second){

                   a=first;

                   b=second;

               }

           T getmax () {

                   return a>b? a : b;

           }

};

int main () {
       mypair <int> myobject (100, 75);

       cout << myobject.getmax();

       return 0;

}


一个实际例子


我将经过一个实际的例子来引导你如何将c/c++库集成到Objective-C代码中。一个例子是集成SQLite库,另外一个例子是讲c++和Objective-C代码进行混编。


SQLite


SQLite是CoreData的底层实现。SQLite性能仍是不错的,由于比较轻量级和更加直接。可是,CoreData在这些方法提供了更好的支持:模型对象匹配,undo和redo功能,批量操做,线程。


使用SQLite的最大好处是:若是你的团队已经很熟悉相关的数据库和SQL,学习的曲线也是很是轻量级的。SQLite一样很容易移植到Android中,这样比就能够在iPhone和Android应用共享相同的数据了。


你能够阅读SQLiteSample工程的源代码。这里我只给你一些重要的提示。


你须要打开命令行,而后书输入sqlite3 students.sql 来建立数据库。这会建立一个新的数据库,而后就能够在这个数据库中建立表,插入和查询数据。你可使用SQL语句建立表和插入数据。


sqlite> CREATE TABLE students (pk INTEGER PRIMARY KEY, name VARCHAR(25));

sqlite> INSERT INTO students (name) VALUES ('khang');
sqlite> INSERT INTO students (name) VALUES ('vo');
sqlite> INSERT INTO students (name) VALUES ('duy');

sqlite> .quit


图9-5更加清楚的展现了在命令行中发生的事情。


你能够在Home文件夹(这个是默认的文件夹,若是你在终端操做时没有修改的话)下找到students.sql文件。你须要把这个文件添加到Xcode中,而后要添加libsqlite3.0.dylib这个库。


- (void)viewDidAppear:(BOOL)animated {
       NSString *path = [[NSBundle mainBundle] pathForResource:@"students" ofType:@"sql"];

       if (sqlite3_open([path UTF8String], &database) == SQLITE_OK) {

       // Get the primary key for all books.
       const char *sql = "SELECT pk, name FROM students";

       sqlite3_stmt *statement;

       // Preparing a statement compiles the SQL query into a byte-code program in theSQLite library.

       // The third parameter is either the length of the SQL string or -1 to read up tothe first null terminator.

       if (sqlite3_prepare_v2(database, sql, -1, &statement, NULL) == SQLITE_OK) {

           // We "step" through the results - once for each row.
           while (sqlite3_step(statement) == SQLITE_ROW) {

                   const unsigned char *name = sqlite3_column_text(statement, 1);

                   NSString *nameString = [NSString stringWithCString:(char *)nameencoding:NSASCIIStringEncoding];

           }

       }

   // "Finalize" the statement - releases the resources associated with thestatement.

   sqlite3_finalize(statement);

} else {

       // Even though the open failed, call close to properly clean up resources.

       sqlite3_close(database);
       NSAssert1(0, @"Failed to open database with message '%s'.",

       sqlite3_errmsg(database));

}

[self.tableView reloadData];

}


这里有一些方法你须要记住:


  • sqlite3_open([path UTF8String], &database) == SQLITE_OK 初始化和将新的数据库对象赋值给你的指针。

  • sqlite3_prepare_v2(database, sql, -1, &statement, NULL) ==SQLITE_OK  执行sql命令和把结果放入statement中。

  • while (sqlite3_step(statement) == SQLITE_ROW): 从执行的statement中遍历结果。




在你的应用中集成c++


你能够绝不费力的将c集成到你的应用中,由于Objective-C是c的超集。可是,当你在应用中集成c++的时候,你须要注意一些细节。


首先,你须要像正常同样的建立c++类的头文件和实现文件(.h和.cpp文件)。而后,你须要把包裹c++文件的Objective-C文件的后缀改成.mm(在iOS环境中这些是Objective-C++文件)。任何想要使用.mm文件的文件也必须像a.mm这样。


你能够查看一下TestC_CPlus这个示例工程。首先,你会看到两个文件,Foo_Cpp.h 和Foo_Cpp.cpp,他们声明了Foo_Cpp这个c++类。而后,经过MyObject.h和MyObject.m这两个Objective-c++文件进行包裹。


最后一步,把这些逻辑集成到你的view controller中。你能够在工程中像正常同样调用MyObject对象。你只须要将把调用的文件后缀改成.mm。


总结


在编程领域中,已经有不少高性能的和由特殊任务的c/c++库。你永远不须要重复发明轮子,或努力的将c/c++代码转换成Objective-c代码。理解c/c++可以帮助你更好的理解库的使用,这样你就可以把他们集成到你的应用中。


Objective-C是c的超集,因此不少c的特性你都已经知道了。我讨论了c编程的一些主要的点,包括指针的概念。你也学到了函数指针,位操做,这些都是c的特性,可以很好的提高性能。


若是你没有编程经验的话,c++比较难以学习和理解。我仅仅讨论了c++一些主要的知识点,c++和Objective-C的主要不一样之处。对于编写一个高要求的c++程序可能信息还不够,可是对于如何将一个已经存在的c++库集成到iPhone应用中已经足够了。


在最后一部分,我使用了一个SQLite的真实的例子展现了如何在Objective-C中使用C。这个并不难,除了一些语法和内存管理上的不一样。对于c++库我并无深刻讨论;我只是展现了如何将c++代码集成到你的iPhone应用中。

相关文章
相关标签/搜索