ใช้ C ++ กับโกโก้แทน Objective-C หรือไม่?


122

ฉันต้องการเขียนแอปพลิเคชันที่ใช้ C ++ และ Cocoa frameworks เนื่องจาก Apple ไม่ได้ทำให้ Carbon 64-bit มีความสามารถ C ++ ดูเหมือนจะเป็นวานิลลาในการใช้งานบน Linux และ Windows แต่ใน MacOS X ดูเหมือนว่าจำเป็นต้องมีโค้ดเฉพาะของ Apple เพิ่มเติม (เช่นกระดาษห่อหุ้ม Obj-C) ดูเหมือนว่า Apple กำลังบังคับให้นักพัฒนาเขียนใน Objective-C แทนที่จะเป็น C ++ แม้ว่าฉันจะผิด

ฉันกำลังพยายามหาเส้นทางในการเขียนโค้ดบน Mac ที่จะทำให้ข้ามแพลตฟอร์มได้ง่าย การเขียนโค้ดใน C ++ สำหรับ Linux / Windows แล้วเขียนซ้ำส่วนใหญ่ใน Objective-C จะไม่มีประสิทธิภาพมาก

มีวิธีการเขียนโค้ดใน C ++ ที่จะรองรับในอนาคตและรองรับใน Xcode หรือไม่? นอกจากนี้หากเป็นไปได้ฉันจะผสม C ++ และ Objective-C ใน Xcode ได้อย่างไร ขอบคุณ

คำตอบ:


110

คุณไม่สามารถเขียนแอปพลิเคชัน Cocoa ใน C ++ ได้ทั้งหมด Cocoa อาศัยความสามารถในการผูกมัดในช่วงปลายของ Objective-C สำหรับเทคโนโลยีหลักหลายอย่างเช่นการเชื่อมโยงคีย์ - ค่าผู้แทน (รูปแบบโกโก้) และรูปแบบการดำเนินการตามเป้าหมาย ข้อกำหนดการผูกล่าช้าทำให้ยากมากที่จะใช้ Cocoa API ในภาษาพิมพ์ที่ จำกัด เวลาคอมไพล์เช่น C ++ ⁱ แน่นอนคุณสามารถเขียนแอป C ++ แท้ที่ทำงานบน OS X ได้ แต่ไม่สามารถใช้ Cocoa API ได้

ดังนั้นคุณมีสองตัวเลือกหากคุณต้องการแชร์โค้ดระหว่างแอพ C ++ บนแพลตฟอร์มอื่นและแอปพลิเคชันที่ใช้โกโก้ของคุณ อย่างแรกคือการเขียนเลเยอร์โมเดลใน C ++ และ GUI ใน Cocoa นี้เป็นวิธีการที่ใช้โดยทั่วไปปพลิเคชันที่มีขนาดใหญ่มากบางคนรวมทั้งMathematica โค้ด C ++ ของคุณจะไม่เปลี่ยนแปลง (คุณไม่จำเป็นต้องมีส่วนขยายของแอปเปิ้ลที่ "ขี้ขลาด" ในการเขียนหรือรวบรวม C ++ บน OS X) เลเยอร์คอนโทรลเลอร์ของคุณน่าจะใช้ประโยชน์จาก Objective-C ++ (อาจเป็นส่วนขยายของ Apple ที่ "ขี้ขลาด" ที่คุณอ้างถึง) Objective-C ++ เป็นส่วนเหนือของ C ++ เช่นเดียวกับที่ Objective-C เป็นส่วนเหนือของ C ใน Objective-C ++ คุณสามารถสร้างข้อความสไตล์ objc ผ่านการโทร (เช่น[some-objc-object callMethod];) จากภายในฟังก์ชัน C ++ ในทางกลับกันคุณสามารถเรียกใช้ฟังก์ชัน C ++ จากภายในรหัส ObjC เช่น:

@interface MyClass {
    MyCPPClass *cppInstance;
}
@end

@implementation MyClass
- (id)init {
    if(self = [super init]) {
        cppInstance = new MyCPPClass();
    }
    return self;
}
- (void) dealloc {
    if(cppInstance != NULL) delete cppInstance;
    [super dealloc];
}
- (void)callCpp {
    cppInstance->SomeMethod();
}
@end

คุณสามารถหาข้อมูลเพิ่มเติมเกี่ยวกับ Objective-C ++ ในภาษา Objective-C คู่มือ จากนั้นเลเยอร์มุมมองสามารถเป็น Objective-C ที่บริสุทธิ์ได้

ตัวเลือกที่สองคือการใช้ชุดเครื่องมือ C ++ ข้ามแพลตฟอร์ม Qtชุดเครื่องมืออาจพอดีกับใบเรียกเก็บเงิน โดยทั่วไปแล้วชุดเครื่องมือข้ามแพลตฟอร์มมักจะถูกผู้ใช้ Mac ดูหมิ่นเพราะพวกเขาไม่ได้รับรายละเอียดรูปลักษณ์และความรู้สึกที่ถูกต้องทั้งหมดและผู้ใช้ Mac คาดหวังว่า UI ของแอปพลิเคชัน Mac จะขัดเกลา อย่างไรก็ตาม Qt ทำได้ดีอย่างน่าประหลาดใจและอาจจะดีพอขึ้นอยู่กับผู้ชมและการใช้แอปของคุณ นอกจากนี้คุณจะสูญเสียเทคโนโลยีเฉพาะ OS X บางอย่างเช่น Core Animation และฟังก์ชัน QuickTime บางอย่างแม้ว่าจะมีการแทนที่โดยประมาณใน Qt API ตามที่คุณระบุ Carbon จะไม่ถูกย้ายไปที่ 64 บิต เนื่องจาก Qt ถูกนำไปใช้กับ Carbon APIs Trolltech / Nokia จึงต้องพอร์ต Qt ไปยัง Cocoa API เพื่อให้เข้ากันได้ 64 บิต ความเข้าใจของฉันคือความสัมพันธ์ถัดไปของ Qt (ปัจจุบันอยู่ในรุ่น candiate) เสร็จสิ้นการเปลี่ยนแปลงนี้และเข้ากันได้กับ OS X แบบ 64 บิตคุณอาจต้องการดูที่มาของ Qt 4.5 หากคุณสนใจที่จะผสานรวม C ++ และ Cocoa API


ⁱในขณะที่ Apple ให้ Cocoa API พร้อมใช้งานใน Java แต่บริดจ์นั้นต้องการการปรับแต่งด้วยมืออย่างกว้างขวางและไม่สามารถจัดการกับเทคโนโลยีขั้นสูงเช่น Key-Value Bindings ที่อธิบายไว้ข้างต้นได้ ขณะนี้พิมพ์แบบไดนามิกภาษาที่ผูกกับรันไทม์เช่น Python, Ruby และอื่น ๆ เป็นตัวเลือกเดียวที่แท้จริงสำหรับการเขียนแอป Cocoa โดยไม่มี Objective-C (แม้ว่าสะพานเหล่านี้จะใช้ Objective-C ภายใต้ประทุนก็ตาม)


ฉันกำลังพยายามพอร์ตแอปพลิเคชัน Ogre3D ขนาดเล็กของฉันดูเหมือนจะเจ็บปวด apple พยายามแปลงทุกคนเป็น Objc หรือนี่คือฟีเจอร์จริงๆ?
jokoon

68

อาจฟังดูงี่เง่า แต่จริงๆแล้วเราสามารถเขียนโค้ด C ++ บริสุทธิ์เพื่อสร้าง GUI สำหรับ Mac OS X ได้ แต่เราต้องเชื่อมโยงกับ Cocoa framework

/*
 * test1.cpp
 * This program shows how to access Cocoa GUI from pure C/C++
 * and build a truly functional GUI application (although very simple).
 * 
 * Compile using:
 *   g++ -framework Cocoa -o test1 test1.cpp
 *
 * that will output 'test1' binary.
 */


#include <CoreFoundation/CoreFoundation.h>
#include <objc/objc.h>
#include <objc/objc-runtime.h>
#include <iostream>

extern "C" int NSRunAlertPanel(CFStringRef strTitle, CFStringRef strMsg,
                               CFStringRef strButton1, CFStringRef strButton2, 
                               CFStringRef strButton3, ...);


int main(int argc, char** argv)
{
    id app = NULL;
    id pool = (id)objc_getClass("NSAutoreleasePool");
    if (!pool)
    {
        std::cerr << "Unable to get NSAutoreleasePool!\nAborting\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("alloc"));
    if (!pool)
    {
        std::cerr << "Unable to create NSAutoreleasePool...\nAborting...\n";
        return -1;
    }
    pool = objc_msgSend(pool, sel_registerName("init"));

    app = objc_msgSend((id)objc_getClass("NSApplication"),
                       sel_registerName("sharedApplication"));

    NSRunAlertPanel(CFSTR("Testing"),
                    CFSTR("This is a simple test to display NSAlertPanel."),
                    CFSTR("OK"), NULL, NULL);

    objc_msgSend(pool, sel_registerName("release"));
    return 0;
}

17
นี่มันวิเศษมาก มีตัวอย่างที่ซับซ้อนกว่านี้หรือไม่? ตัวอย่างเช่นการเปิด NSWindow?
imallett

test1.cpp: ในฟังก์ชัน 'int main (int, char **)': test1.cpp: 26: 48: error: ไม่สามารถแปลง 'Class {aka objc_class *}' เป็น 'id {aka objc_object *}' ในรหัสเริ่มต้น สระ = objc_getClass ("NSAutoreleasePool"); ^ test1.cpp: 41: 61: ข้อผิดพลาด: ไม่สามารถแปลง 'Class {aka objc_class *}' เป็น 'id {aka objc_object *}' สำหรับอาร์กิวเมนต์ '1' ถึง 'objc_object * objc_msgSend (id, SEL, ... )' sel_registerName ( "sharedApplication")); ^
Jichao

6
@Jichao ดูความเข้ากันได้ของ Clang กับประเภท Objective-C ภายใน - การแก้ไขทำได้ง่าย: แทนที่objc_getClassด้วย(id)objc_getClass
Dmitry Isaev

ฉันจะใช้ std :: string เพื่อตั้งค่าเช่นได้อย่างไร ชื่อของแผงการแจ้งเตือน? ฉันลองใช้ c_str () แล้วเหมือนกัน แต่ไม่มีอะไรได้ผล ...
mdre

1
สิ่งนี้ไม่รวบรวมอีกต่อไปใน macOS Catalina
JC Rocamonde

18

ใช่คุณสามารถใช้ C ++ (เช่นเขียนในไฟล์ * .cpp) และผสม C ++ และ Objective-C ในไฟล์ * .mm ได้ด้วย (รหัส Objective-C มาตรฐานจะถูกเก็บไว้ในไฟล์ * .m)

แน่นอนคุณยังคงต้องใช้ Objective-C สำหรับอินเทอร์เฟซผู้ใช้ของคุณและสร้าง Objective-C wrapper สำหรับออบเจ็กต์ C ++ ของคุณ อีกทางเลือกหนึ่งคือการเปลี่ยนไปใช้Qtซึ่งเป็น C ++ Framework ที่รองรับ Windows, Mac OS X และ Linux - และจะวางจำหน่ายภายใต้ LGPL ในเวอร์ชันถัดไป 4.5


23
โปรดทราบว่าหากคุณใช้ Qt แอปของคุณจะดูด แอพที่ใช้ Qt จะดูไม่เหมือนแอพของ Mac (ตัวอย่างเช่นดู Google Earth)
Peter Hosey

15
Peter: นั่นไม่จริงเลย แอปที่ใช้ Qt สามารถมีลักษณะและความรู้สึกเหมือนกับแอป Mac ทั่วไปคุณเพียงแค่ต้องทำการปรับแต่งตามแพลตฟอร์มซึ่งเป็นสิ่งที่ง่ายกว่าการเขียน GUI แบบเนทีฟบนแต่ละแพลตฟอร์ม
Mike McQuaid

12
ไมค์คุณเข้าใจผิด ในบรรดาข้อบกพร่องอื่น ๆ แอพที่ใช้ Qt บน mac ไม่ได้ใช้การควบคุมแบบเนทีฟเลยและไลบรารี Qt จะทำการวาดเองทั้งหมด ซึ่งหมายความว่าแอป Qt ไม่ได้รับการเร่งฮาร์ดแวร์ใด ๆ สำหรับการเรนเดอร์ 2D แอปเหล่านี้จะไม่ซิงค์กับการเปลี่ยนแปลง UI ที่ Apple ทำกับการควบคุมมาตรฐานและแอป Qt ไม่สามารถให้การปฏิบัติตามข้อกำหนด ADA หรือความสามารถในการเขียนสคริปต์เว้นแต่คุณจะสร้างสิ่งเหล่านั้นขึ้นมาใหม่ ล้อตัวเอง กล่าวอีกนัยหนึ่งคืออย่าใช้แอพ Qt บน Mac Google สามารถหลีกเลี่ยงได้: คุณทำไม่ได้
NSResponder

13
พวกเขาใช้การควบคุมแบบเนทีฟนั่นคือเหตุผลที่ Qt มีเวอร์ชันโกโก้และคาร์บอน มีปัญหาอื่น ๆ แต่ผู้คนจำนวนมากส่งแอปพลิเคชัน Qt บน Mac และทำงานได้ดี (และสมบูรณ์แบบด้วยการปรับแต่งเล็กน้อย)
Mike McQuaid

2
การใช้การควบคุมแบบเนทีฟไม่ได้หมายความว่าจะมีลักษณะและความรู้สึกเหมือนแอปเนทีฟ สิ่งที่ทำให้เกิดความรู้สึกดั้งเดิมคือความแตกต่างของแต่ละ OS หากคุณปรับแต่งแอปของคุณให้สัมผัสได้ในแพลตฟอร์มที่เฉพาะเจาะจงแอปนั้นจะไม่รู้สึกเหมือนอยู่ในแพลตฟอร์มอื่น และการปรับพฤติกรรมเล็ก ๆ อย่างละเอียดในเลเยอร์ที่ถูกทำให้เป็นนามธรรมนั้นยากกว่าการทำบนเลเยอร์เนทีฟเสมอ
eonil

9

ใช่คุณสามารถผสมได้

คุณต้องใช้ Objective-C เพื่อดำเนินการกับวัตถุ GUI ของคุณโดยตรงและรับการแจ้งเตือนจากวัตถุเหล่านั้น

วัตถุ Objective-C เหล่านี้สามารถเรียกใช้ตรรกะ C ++ ได้โดยตรงหากคุณใส่ไว้ในไฟล์. mm แทนที่จะเป็นไฟล์ Objective-C .m ที่บริสุทธิ์ โปรดทราบว่าคุณอาจเห็นคำแนะนำที่เก่ากว่า (มาก) แนะนำให้ใช้ตัวพิมพ์ใหญ่. M เพื่อระบุ Objective-C ++ แต่สิ่งนี้ไม่สม่ำเสมอและอาจทำให้คุณสับสนรวมทั้งคอมไพเลอร์

คุณไม่จำเป็นต้องรวมอ็อบเจ็กต์ C ++ แต่ละตัว แต่โค้ด Objective-C ของคุณจะต้องมีพอยน์เตอร์

Apple ไม่เผยแพร่ตัวอย่างที่แสดงวิธีการทำอีกต่อไป

มีวิดีโอที่ยอดเยี่ยมโดย Peter Steinberger ซึ่งจัดขึ้นที่ Realm [Objective] C ++: What could go wrong? ฉันขอแนะนำอย่างยิ่งสำหรับทุกคนที่ยังใช้ Objective-C ++ และคุณสามารถอ่านการถอดเสียงได้อย่างรวดเร็ว


@SteveS ลิงค์ของคุณเสียด้วย
fferri

@fferi - ลิงก์ Steinberger ด้านบนได้รับการแก้ไขแล้ว Carbon Cocoa Integration มาจากปี 2550 จาก developer.apple.com Apple ได้ลบมันออกไป สิ่งนี้บ่งชี้ว่าคุณไม่ควรเขียนโค้ดใหม่โดยใช้ Carbon API ณ จุดนี้แม้แต่การรักษาโค้ดที่มีอยู่โดยใช้ Carbon ก็มีความเสี่ยง อ้างถึงคำตอบที่ยอมรับสำหรับคำถามนี้หรือคำถามนี้ หากคุณต้องการผสม C ++ / Objective C แต่คุณไม่ควรใช้ Carbon ที่กล่าวว่าที่นี่: Carbon-Cocoa-Integration
SteveS

4

หากคุณต้องการใช้วานิลลา C ++ ธรรมดาสิ่งนี้ได้รับการสนับสนุนอย่างแน่นอนและไม่แตกต่างจากแพลตฟอร์มอื่น ๆ Xcode ยังมีเทมเพลตภายใต้ไฟล์> โครงการใหม่> ยูทิลิตี้บรรทัดคำสั่ง> เครื่องมือ C ++ นอกจากนี้ไลบรารีโอเพนซอร์สยอดนิยมจำนวนหนึ่ง (libcurl, libxml2, sqlite ฯลฯ ) มาพร้อมกับ OS X และพร้อมใช้งานสำหรับการลิงก์แบบไดนามิก คุณไม่จำเป็นต้องใช้โกโก้หรืออะไรก็ตามที่เฉพาะเจาะจงของ Apple หากคุณไม่ต้องการ

หากคุณไม่ต้องการที่จะใช้โกโก้ในบางส่วนของแอปของคุณให้ดูที่วัตถุประสงค์-C ++ คุณสามารถผสม C ++ และ Objective-C ในไฟล์เดียวกันได้โดยให้นามสกุลเป็น. mm หรือคลิกขวาที่ไฟล์ใน Xcode แล้วเลือก Get Info> General จากนั้นเปลี่ยน File Type เป็น sourcecode.cpp.objcpp ตัวเลือกที่สองมีประโยชน์หากคุณมีไฟล์. cpp ที่คุณต้องการใช้ Objective-C ภายใน #ifdef เฉพาะสำหรับ Mac


1
BTW เทมเพลต C ++ (มีประโยชน์จริงๆ) หายไปพร้อมกับ Xcode เวอร์ชันล่าสุด (4.x และ 5.x)
Jay

1

แม้จะเป็นคำถามเก่าแก่หลายปี ...

ฉันได้ลองทำ C ++ wrapper ของ Cocoa บางคลาสแล้ว

มันเป็นประสบการณ์ที่ดีทีเดียว C ++ ให้ความปลอดภัยประเภทที่ดีกว่า Objective-C และทำให้ฉันเขียนโค้ดน้อยลง แต่เวลาในการรวบรวมและความปลอดภัยของหน่วยความจำแย่ลง เป็นไปได้ แต่คุณสมบัติที่ใช้ไดนามิกบางอย่างไม่สะดวกในการจัดการ ฉันคิดว่ามันไม่สมเหตุสมผลที่จะจัดการกับ C ++

อย่างไรก็ตามในที่สุดโครงการของฉันก็ถูกยกเลิกเนื่องจากการประกาศของ Swift มันเคลียร์เหตุผลทั้งหมดที่ฉันต้องการใช้ C ++ ในตอนแรกและให้มากขึ้นเรื่อย ๆ


0

หากคุณกำลังเขียนโปรแกรมกราฟิกอย่างหมดจดเช่นคุณกำลังวาดภาพทุกอย่างโดยใช้รหัสพิจารณาopenFrameworks เป็นภาษาโปรแกรมกราฟิกแบบโอเพนซอร์สที่สร้างขึ้นจาก C / C ++ มันมีaddonsที่ช่วยให้คนที่จะขยายภาษา พวกเขามีaddon สำหรับ iPhone ฉันเชื่อว่ามันมาพร้อมกับไลบรารีและโปรเจ็กต์ XCode ที่จะช่วยคุณรวบรวมแอพสำหรับ iPhone และ iPod touch

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.