C++ 語法細節

Johnny Chang
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

--

--