C++ 語法細節
6 min readJun 25, 2023
從Junior到Senior的門檻: 語法細節
使用inline template取代define
- 在C裡面我們常使用define來處理WHO_IS_MAX的問題,但編譯器可能會忽略一些潛在問題,如a, b為不同Type,在C++請使用template + inline function, 可以避免a,b不同type的狀況
// Old define method in C
#define WHO_IS_MAX(a, b) ((a)>(b)?a:b)
// Use template in C++
template<typename T>
inline const T& WHO_IS_MAX(const T& a , const T& b){
return a>b?a:b;
}
Copy and Assignment
- Copy 以及 Assignment的差別
class Test {
public:
Test() {}
Test(const Test& t){
cout << "Copy constructor called " << endl;
}
Test& operator=(const Test& t){
cout << "Assignment operator called " << endl;
return *this;
}
};
int main() {
Test t1, t2;
// Assignment
t2 = t1;
// Copy
Test t3 = t1;
getchar();
return 0;
}
Assignment operator called
Copy constructor called
- 大多數時候,Copy and Assignment是Compiler產生的,class Test中我們並未定義copy and assignment operator
class Test {
public:
Test() {}
};
int main() {
Test t1, t2;
// Assignment
t2 = t1;
// Copy
Test t3 = t1;
getchar();
return 0;
}
- 用private function來避免Compiler自動產生,並生成Compiler Failed
class Test {
private:
Test(const Test& t);
Test& operator=(const Test& t);
public:
Test() {}
};
int main() {
Test t1, t2;
// Failed
t2 = t1;
// Failed
Test t3 = t1;
getchar();
return 0;
}
virtual function 使用方法
- 對於virtual function,可以覆寫原先Base function建議參考如下
struct Base {
virtual void f() {
std::cout << "base\n";
}
};
struct Derived : Base {
void f() override {
std::cout << "derived\n";
}
};
int main() {
Base b;
Derived d;
Base& br = b; // br is Base& from Base
Base& dr = d; // dr is Base& from Derived
br.f(); // print base
dr.f(); // print derived
Base* bp = new Base; // bp is Base*
Base* dp = new Derived; // dp is Base*
bp->f(); // print base
dp->f(); // print derived
delete bp;
delete dp;
br.Base::f(); // print base
dr.Base::f(); // print base
}
- 對於有virtual function的class,destructor 一定要有virtual,如下所示因為Base class並沒有destructor,所以是undefined behavior
class Base {
virtual void f();
};
class Derived : Base {};
void f() {
Base *b = new Derived();
delete b;
}
永遠使用Smart Pointer來 Handle malloc / new
- For data buffer in C,使用 array 或 vector來取代
// C case
uint8_t pointer = (uint8_t*)malloc(100);
// C++ array case
std::shared_ptr<std::array<uint8_t,100>> pointer(std::make_shared<std::array<uint8_t,100>>());
// C++ vector
std::shared_ptr<std::vector<uint8_t>> pointer(std::make_shared<std::vector<uint8_t>>());
延後定義變數的時間
- 因為Return / Exception 可能導致初始化的變量沒有用到
void TestFunction(void * ptr) {
std::string output("Great")
if (!ptr)
return
// move define string here
std::string output("Great")
std::cout << "Use String Now" << output << std::endl;
}
Const 用法 in C++
- Variable Const
const int* ptr; // ptr is a pointer to constant int
int *const ptr; // ptr is a constant pointer to int
const int* const ptr; // all is const
- Member Function Const
class MyClass {
public:
int getValue() const; // const 函數聲明不能改變任何class member
private:
int myValue;
};
// 在類外部定義 const 函數
int MyClass::getValue() const {
// 不要修改成員變量
// 只返回成員變量的值
return myValue;
}
盡量使用 std::move 來避免無謂的Copy/Assignment
- vector 的使用
std::vector<MyClass> vec;
MyClass obj;
// 將 obj 的所有權移動到容器中
vec.push_back(std::move(obj));
// 從容器中取出元素的所有權
MyClass extractedObj = std::move(vec[0]);
// std::move後的obj避免再使用
- unique_ptr 的使用
std::unique_ptr<int> ptr1 = std::make_unique<int>(42);
std::unique_ptr<int> ptr2 = std::move(ptr1); // 移動 ptr1 的資源到 ptr2